Go map 竟然也会发生内存泄露?( 二 )

293 MB293 MB293 MB当 val 小于 128B 时,初始化 map 后内存占用量一直不变 。原因是 put 操作只是在 bucket 里原地写入 val,而 delete 操作则是将 val 清零,bucket 本身还在 。因此,内存占用大小不变 。
而当 val 大小超过 128B 后,bucket 不会直接放 val,转而变成一个指针 。我们将 N 设为 129,运行程序:
0 MB197 MB38 MB虽然 map 的 bucket 占用内存量依然存在,但 val 改成指针存储后内存占用量大大降低 。且 val 被删掉后,内存占用量确实降低了 。
总之,map 的 buckets 数只会增,不会降 。所以在流量冲击后,map 的 buckets 数增长到一定值,之后即使把元素都删了也无济于事 。内存占用还是在,因为 buckets 占用的内存不会少 。
对于 map 内存泄露的解法:

  • 重启;
  • 将 val 类型改成指针;
  • 定期地将 map 里的元素全量拷贝到另一个 map 里 。
好在一般有大流量冲击的互联网业务大都是 toC 场景,上线频率非常高 。有的公司能一天上线好几次,在问题暴露之前就已经重启恢复了,问题不大 。

经验总结扩展阅读