golang slice内存泄露回收

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


1. 问题现象

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

v2-b8e873faac69c75421e0dfb4e2454057_b.jpg

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/

v2-1d2a3b82874d8304b0fcb31d2f3b9190_b.jpg

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

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

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

v2-1462de063a4ba3728d8a18c8740fc21e_b.jpg

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

v2-3d481587396d0c9547bc1e6cc6810d7c_b.jpg

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。


参考链接

gfw.go101.org/article/m

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值