golang slice 内存泄露_golang slice内存泄露回收 - Go语言中文社区

golang slice 内存泄露_golang slice内存泄露回收


最近项目开发中遇到一个问题:在程序中大量使用golang slice导致内存占用暴涨。经过一番分析与定位最终解决了问题,把过程记录下来与大家分析。

1. 问题现象

  • 程序正常运行中突然出现内存占用飙升,使用htop命令查看,程序内存占用排第一;
  • 使用free -m命令查看,发现可用内存为0;
  • 由于程序占用内存过多,导致linux虚拟机响应缓慢卡顿;
  • 使用kill命令杀掉进程后,内存释放,虚拟机恢复正常。

de627959b53be035f7b9a0315464968d.png

2. 查看内存占用情况

因为是内存问题,所以首先使用golang的pprof包进行查看heap和alloc内存分配详情。

2.1 引入pprof包

//在import中添加pprof包
_ "net/http/pprof"

2.2 打开pprof包web服务端口

//指定pprof对外提供的http服务的ip和端口,配置为0.0.0.0表示可以非本机访问
go func() {
   http.ListenAndServe("0.0.0.0:9999", nil)
}()

2.3 程序启动后查看pprof服务端口是否启用

netstat -antp|grep 9999
tcp6       0      0 :::9989                 :::*                    LISTEN      28294/program

2.4 在网页上查看pprof信息

http://127.0.0.1:9999/debug/pprof/

930b2a974c82e6c6a04ba22333b4803d.png

2.5 更丰富的命令和信息,还是要通过命令行查看

go tool pprof http://127.0.0.1:9999/debug/pprof/heap

连接上后,可以使用top命令查看内存使用排行

b91ee6c2f31392919166c5f23ee3afdc.png

然后,使用list命令直接可以查看到具体是哪一行分配了多少内存

aea0c3921c6e9e344cb824f6c432dbca.png

3. 分析问题

由于pprof信息显示,大量内存都是由于在slice的append方法中分配的。于是又回顾了一下slice的原理和坑。

3.1 slice原理

golang中slice是对数组的引用,底层实现实际上还是数组。对slice一定要谨慎使用append操作。如果cap未变化时,slice是对数组的引用,并且append会修改被引用数组的值。append操作导致cap变化后,会复制被引用的数组,然后切断引用关系。

3.2 golang关于slice的内存回收

经过分析和查资料发现,网上总结的容易导致内存不能及时回收的情况:

3.2.1截取长slice中的一段导致长slice未释放。

由于底层都是数组,如果截图长slice的一段,其实相当于引用了底层数组中的一小段。只要还有引用,golang的gc就不能回收数组。这种情况导致未使用的数组空间,未及时回收。

解决方案,新建一个长度为0的slice,将需要的一小段slice使用append方法添加到新的slice。再将原来的slice置为nil。


3.2.2 配合gc,及时将不再使用的slice置为nil

如果slice中包含很多元素,再只有一小部分元素需要使用的情况下。建议重新分配一个slice将需要保留的元素加入其中,将原来的长slice整个置为nil。

参考链接

https://gfw.go101.org/article/memory-leaking.html

版权声明:本文来源CSDN,感谢博主原创文章,遵循 CC 4.0 by-sa 版权协议,转载请附上原文出处链接和本声明。
原文链接:https://blog.csdn.net/weixin_34513260/article/details/112098819
站方申明:本站部分内容来自社区用户分享,若涉及侵权,请联系站方删除。
  • 发表于 2021-06-26 16:45:25
  • 阅读 ( 806 )
  • 分类:Go

0 条评论

请先 登录 后评论

官方社群

GO教程

猜你喜欢