Golang

关注公众号 jb51net

关闭
首页 > 脚本专栏 > Golang > Golang内存泄露

Golang内存泄露场景与定位方式的实现

作者:每天一个秃顶小技巧

Golang有自动垃圾回收机制,但是仍然可能会出现内存泄漏的情况,本文主要介绍了Golang内存泄露场景与定位方式的实现,具有一定的参考价值,感兴趣的可以了解一下

一、产生原因

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

二、排查方式

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

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

3.1 通过 pprof 的命令行分析 heap

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

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

top 命令, 默认能列出当前程序中内存占用排名前 10 的函数. 如图. 当时进行到这一步的时候, 我就非常惊讶, 因为 time.NewTimer 居然占据了 6 个多 G 的内存.

img

list <函数名>, 展现函数内部的内存占用. 使用 list time.NewTimer 查看了该函数的内部, 真相大白了, 原来每次调用 NewTimer 都会创建一个 channel, 还会生成一个结构体 runtimeTimer, 应该就是这两个地方内存没有释放造成的内存泄露.

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 就是封装了一层的 NewTimertime.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内存泄漏的常见可能原因有哪些:

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

五、参考链接

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

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

到此这篇关于Golang内存泄露场景与定位方式的实现的文章就介绍到这了,更多相关Golang内存泄露内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

您可能感兴趣的文章:
阅读全文