golang的内存回收策略

RSS( Resident Set Size )常驻内存集合大小,表示相应进程在RAM中占用了多少内存,并不包含在SWAP中占用的虚拟内存。即使是在内存中的使用了共享库的内存大小也一并计算在内,包含了完整的在stack和heap中的内存。

VSZ (Virtual Memory Size),表明是虚拟内存大小,表明了该进程可以访问的所有内存,包括被交换的内存和共享库内存。

MADV_DONTNEED:内核会在进程的页表中将这些页标记为 “未分配”,从而进程的 RSS 就会尽快释放和变小。OS 后续可以将对应的物理页分配给其他进程。
MADV_FREE:内核只会在页表中将这些进程页面标记为可回收,在需要的时候才回收这些页面。

其中MADV_FREE是Go 1.12版本才引入的,官网上的介绍如下:


On Linux, the runtime now uses MADV_FREE to release unused memory. This is more efficient but may result in higher reported RSS. The kernel will reclaim the unused data when it is needed. To revert to the Go 1.11 behavior (MADV_DONTNEED), set the environment variable GODEBUG=madvdontneed=1.
大意就是使用MADV_FREE方式,程序内存不会立刻回收,即RSS值不会立刻下降,只有当OS内存紧缺时才会回收Go程序的内存返回给OS;而Go 1.11以及之前的版本默认采用的是 MADV_DONTNEED方式,程序RSS值下降很快。因此如果需要使程序内存占用下降很快的话,可设置环境变量GODEBUG=madvdontneed=1。
注:Linux 4.5及之后的版本中,默认使用MADV_FREE方式。

runtime/mem_linux.go源码里注释如下:
在这里插入图片描述

从1.16开始由MADV_FREE方式切换为MADV_DONTNEED方式

Go1.12 以前

Go Runtime 在 Linux 上默认使用的是 MADV_DONTNEED 策略。

  // 没有任何奇奇怪怪的判断
 madvise(v, n, _MADV_DONTNEED)

从整体效果来看,进程 RSS 可以下降的比较快,但从性能效率上来看差点。

#Go1.12-Go1.15

当前 Linux 内核版本 >=4.5 时,Go Runtime 在 Linux 上默认使用了性能更为高效的 MADV_FREE 策略。

 var advise uint32
 if debug.madvdontneed != 0 {
  advise = _MADV_DONTNEED
 } else {
  advise = atomic.Load(&adviseUnused)
 }
 if errno := madvise(v, n, int32(advise)); advise == _MADV_FREE && errno != 0 {
  // MADV_FREE was added in Linux 4.5. Fall back to MADV_DONTNEED if it is
  // not supported.
  atomic.Store(&adviseUnused, _MADV_DONTNEED)
  madvise(v, n, _MADV_DONTNEED)
 }

从整体效果来看,进程RSS 不会立刻下降,要等到系统有内存压力了才会释放占用,RSS 才会下降。

强制使用MADV_DONTNEED

GODEBUG=madvdontneed=1 go run

https://mp.weixin.qq.com/s/l4oEJdskbWpff1E3tTNUxQ

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

a...Z

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值