本文介绍: 循环引用:如果两个多个对象相互引用,且没有其他对象引用它们,那么它们就会被垃圾回收机制误认为是仍在使用对象,导致内存泄漏全局变量:在Golang中,全局变量生命周期程序生命周期相同。如果一个全局变量创建后一直存在内存中,那么它所占用内存就无法被回收,可能会导致内存泄漏。未关闭文件句柄:如果程序打开文件句柄没有关闭它们,那么这些文件句柄所占用的内存就无法被回收,可能会导致内存泄漏。大量的临时对象。

个人博客

一、产生原因

Golang自动垃圾回收机制,但是仍然可能会出现内存泄漏的情况。以下是Golang内存泄漏的常见可能原因

  1. 循环引用:如果两个多个对象相互引用,且没有其他对象引用它们,那么它们就会被垃圾回收机制误认为是仍在使用的对象,导致内存泄漏。
  2. 全局变量:在Golang中,全局变量生命周期与程序的生命周期相同。如果一个全局变量创建后一直存在于内存中,那么它所占用的内存就无法被回收,可能会导致内存泄漏。
  3. 关闭的文件句柄:如果程序打开了文件句柄没有关闭它们,那么这些文件句柄所占用的内存就无法被回收,可能会导致内存泄漏。
  4. 大量的临时对象:如果程序创建了大量的临时对象,但没有及时释放它们,那么这些对象所占用的内存就无法被回收,可能会导致内存泄漏。
  5. goroutine泄漏常见泄露场景例如协程发生阻塞,Go运行时并不会将处于永久阻塞状态协程杀掉,因此永久处于阻塞状态协程所占用的资源将永得不到释放。
  6. time.Ticker未关闭导致泄漏:当一个time.Timer值不再被使用,一段时间后它将被自动垃圾回收掉。 但对于一个不再使用time.Ticker值,我们必须调用它的Stop方法结束它,否则它将永远不会得到回收

二、排查方式

如果出现内存泄漏,可以使用以下方式进行分析,找出内存泄漏的原因并进行修复

  1. 使用 Go 语言自带pprof 工具进行分析pprof 可以生成程序的 CPU 和内存使用情况的报告,帮助开发者找出程序中的性能瓶颈和内存泄漏问题可以通过代码添加 import _ "net/http/pprof"http.ListenAndServe("localhost:6060", nil)开启 pprof 工具
  2. 使用 Golang 内置runtime 包进行分析runtime 包提供了一些函数,包括 SetFinalizerReadMemStatsStack 等,可以帮助开发者了解程序的内存使用情况和内存泄漏问题
  3. 使用第三方工具进行分析例如,可以使用 go-torch 工具生成火焰图,帮助开发者找出程序中的性能瓶颈和内存泄漏问题
  4. 使用 go vet 工具进行静态分析go vet 可以检查程序中的常见错误和潜在问题,包括内存泄漏问题
  5. 代码审查。开发者可以通过代码审查来找出程序中的潜在问题和内存泄漏问题

三、通过 pprof 的命令排查内存泄露问题

3.1 通过 pprof 的命令行分析 heap

命令行执行命令: go tool pprof -inuse_space [&lt;http://127.0.0.1:9999/debug/pprof/heap&gt;](<http://spark-master.x.upyun.com/debug/pprof/heap&gt;)

这个命令的作用是, 抓取当前程序已使用的 heap. 抓取后, 就可以进行类似于 gdb交互操作.

img

img

3.2 修改 for ... select ... time.After 造成的内存泄露

原来程序中存在如下代码:

for {
		select {

		case a := <-chanA:
			...

		case b := <-chanB:
			....

		case <-time.After(20*time.Minutes):
			return nil, errors.New("download timeout")
	}

time.After 就是封装了一层的 NewTimer, time.After源码:

func After(d Duration) <-chan Time {
	return NewTimer(d).C
}

修复错误, 只调用一次 NewTimer:

downloadTimeout := time.NewTimer(20 * time.Minute)
// 添加关闭时退出操作
defer downloadTimeout.Stop()

for {
		select {

		case a := <-chanA:
			...

		case b := <-chanB:
			....

		case <-downloadTimeout.C:
			return nil, errors.New("download timeout")
	}

四、总结

通过篇文章我们了解到Golang内存泄漏的常见可能原因哪些

  1. 循环引用:如果两个多个对象相互引用,且没有其他对象引用它们,那么它们就会被垃圾回收机制误认为是仍在使用的对象,导致内存泄漏。
  2. 全局变量:在Golang中,全局变量的生命周期与程序的生命周期相同。如果一个全局变量被创建后一直存在于内存中,那么它所占用的内存就无法被回收,可能会导致内存泄漏。
  3. 未关闭的文件句柄:如果程序打开了文件句柄但没有关闭它们,那么这些文件句柄所占用的内存就无法被回收,可能会导致内存泄漏。
  4. 大量的临时对象:如果程序创建了大量的临时对象,但没有及时释放它们,那么这些对象所占用的内存就无法被回收,可能会导致内存泄漏。
  5. goroutine泄漏比较常见的泄露场景,例如协程发生阻塞,Go运行时并不会将处于永久阻塞状态的协程杀掉,因此永久处于阻塞状态的协程所占用的资源将永得不到释放。
  6. time.Ticker未关闭导致泄漏:当一个time.Timer值不再被使用,一段时间后它将被自动垃圾回收掉。 但对于一个不再使用的time.Ticker值,我们必须调用它的Stop方法结束它,否则它将永远不会得到回收。

然后介绍了相关排查工具以及pprof如何排查内存泄露问题。

五、参考链接

1.一些可能的内存泄漏场景

2.使用 pprof 排查 Golang 内存泄露

原文地址:https://blog.csdn.net/qq_42009262/article/details/130996634

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任

如若转载,请注明出处:http://www.7code.cn/show_21016.html

如若内容造成侵权/违法违规/事实不符,请联系代码007邮箱suwngjj01@126.com进行投诉反馈,一经查实,立即删除

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注