golang中省略返回值造成内存泄漏

golang中省略返回值造成内存泄漏,第1张

概述我已经两次因为不恰当的省略go中的函数返回值,一次造成MySql的too many connection错误,一次造成严重的内存泄漏。所以在这里大家分享一下这个问题和解决办法,也提醒自己以后不要再犯类似的错了。 众所周知,go中的函数可以返回多个值。但很多时候我们并不需要所有的值,而且go中定义了一个变量必须使用才可以,不然会报错。所以对于不需要的返回值,一般的 *** 作方法就是省略: for _,va

我已经两次因为不恰当的省略go中的函数返回值,一次造成MysqL的too many connection错误,一次造成严重的内存泄漏。所以在这里大家分享一下这个问题和解决办法,也提醒自己以后不要再犯类似的错了。

众所周知,go中的函数可以返回多个值。但很多时候我们并不需要所有的值,而且go中定义了一个变量必须使用才可以,不然会报错。所以对于不需要的返回值,一般的 *** 作方法就是省略:

for_,value:=rangeslice{	//....	}

一个典型就是上面的range。range可以返回两个值:如果后面是数组或者切片,第一值就是index索引号。如果range后面是map类型,第一值就是map的键key。第二值就是数据里或者map中具体的值了。很多时候我们不需要第一个值,所以就像上面代码中写的一样,直接省略就好。这样的处理办法在一般情况下是没有什么问题,但有的情况下就会出现严重的问题。比如下面这段代码:

for{	_,err=http.Post(url,"",nil)	iferr!=nil{		fmt.Println(err)	}	time.Sleep(Interval)}

因为不需要返回的数据,只要访问不发生错误就行,所以我直接把第一个值省略点了。然后运行,然后就看到任务管理器里面看到,程序进程的内存一直飞增。厉害的时候刷新一次能增加2-3MB!当时就觉得有点蒙了,因为在循环中的就这小部分,而这部分用的都是官方的库。当时的念头就是难道是官方库存在内存泄漏,想想又觉得这是不可能的。

在Google上搜了半天,打算用pprof。说实话这个工具我真不会用,只是当时也没办法,不管合适不合适就直接上了。果然分析结果对我来说就像天书一样。胡乱看看,只是发现goroutine增长的非常快。点进去看看,满屏的参数也看不懂。这个时候我看到bufio这个包,突然想到以前遇到的一次错误。

前些时候在使用go调用MysqL的时候会出现too many connection的错误。当时的一个原因就是我省略了一个返回值,于是资源一直没有释放,最后耗尽了MysqL的连接数。这次会不会一样?于是我改了下上面的代码:

varresP*http.Responsefor{	resp,nil)	resp.Body.Close()	iferr!=nil{		fmt.Println(err)	}time.Sleep(Interval)}

然后再运行,问题解决了!

对比两次的代码,我发现了问题的所在:除了因为我省略的参数里面有需要释放的资源,还因为两次省略的参数都是指针!这才是关键!指针本质只是一个地址,并不是值的本身。所以虽然我们省略了返回值,也只少创建了一个指针而已。而在我们调用的函数里面,已经把变量创建好了,该消耗的内存已经消耗掉了。随着不断的循环,没有释放的资源越来越多,内存消耗也就越来越大了。这就是问题的关键。

第一次遇到这个问题的时候,简单的以为虽然我省略了返回值,但是go还是会创建个匿名变量什么的,会造成内存的泄漏。知道这次再遇到这样的问题,才想明白问题的本质原因是什么。

这次的BUG,给我的教训就是,如果go里面一个函数返回的值是指针,一定要小心,不要轻易省略。不然很有可能造成已经在函数里面申请的内存空间,因为无法释放而不断的积累。而go文档里面强调要手动释放的资源,比如http.Response.Body或者是os.file,也不要轻易的省略(一般也不会省略的……),而且一定要记住释放,使用defer是最靠谱的(不过也有一个坑……)。

总结

以上是内存溢出为你收集整理的golang中省略返回值造成内存泄漏全部内容,希望文章能够帮你解决golang中省略返回值造成内存泄漏所遇到的程序开发问题。

如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/langs/1290338.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-06-09
下一篇 2022-06-09

发表评论

登录后才能评论

评论列表(0条)

保存