博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
golang中省略返回值造成内存泄漏
阅读量:5739 次
发布时间:2019-06-18

本文共 1585 字,大约阅读时间需要 5 分钟。

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

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

for _,value := range slice{	//....	}

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

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

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

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

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

var resp *http.Responsefor {	resp, err = http.Post(url, "", nil)	resp.Body.Close()	if err != nil {		fmt.Println(err)	}        time.Sleep(Interval)}

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

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

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

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

转载于:https://my.oschina.net/waknow/blog/293852

你可能感兴趣的文章
ASP.NET 短路由配置
查看>>
教程-(SQL DBE、ADO连接)+(Firebird火鸟+DbExpress)+(VF DBF数据库)+(DB Paradox)
查看>>
php获胜的算法的概率,它可用于刮,大转盘等彩票的算法
查看>>
C语言函数指针
查看>>
Androidproject夹
查看>>
YUV编码格式
查看>>
python 安装easy_install和pip
查看>>
Open DJ备份与恢复方案
查看>>
Oracle创建用户设置权限
查看>>
当大数据遭遇深不可测的人性
查看>>
报错:tr was not declared in this scope
查看>>
Java反射
查看>>
批量扫描互联网无线路由设备telnet,并获取WIFI密码
查看>>
ubuntu中eclipse无法识别android手机问题
查看>>
HDU 4978 A simple probability problem
查看>>
windows2003 IIS6.0右键属性没有asp.net选项卡的解决办法
查看>>
MongoDB JAVA API Filters
查看>>
用spring-data-redis实现类似twitter的网站(转)
查看>>
Unity3D 之武器系统冷却功能的实现方式
查看>>
安卓中运行报错Error:Execution failed for task ':app:transformClassesWithDexForDebug'解决
查看>>