• 设为首页
  • 点击收藏
  • 手机版
    手机扫一扫访问
    迪恩网络手机版
  • 关注官方公众号
    微信扫一扫关注
    迪恩网络公众号

Go贡献者minux.ma关于内存泄漏问题的详细解释

原作者: [db:作者] 来自: [db:来源] 收藏 邀请

目前Go使用的GC是个保守的GC,换句通俗的话说就是宁可少释放垃圾不可误释放还在用的内存;这个反映在设计上就是会从堆栈、全局变量开始,把所有可能是指针的字全部当作指针,遍历,找到所有还能访问到的内存中的对象,然后把剩下的释放。

那么如何判断一个字(uintptr)可能是指针呢?大家知道Go的内存分配是参考的tcmalloc,并做了一些改动,原先tcmalloc是使用类似页表的树形结构保存已经从操作系统中获得的内存页面,Go使用了另外一个办法。由于Go需要维护每个内存字的一些状态(比如是否包含指针?是否有finalizer?是否是结构体的开始?还有上面提到的是否还能访问到的状态),综合在一起是每个字需要4bit信息;于是Go就先找一片区域(arena),以不可访问的权限从操作系统那里申请过来(mmap的prot参数是PROT_NONE),然后根据每一个uintptr对应4位申请一片RW的内存(bitmap)与前面的arena对应;这样已知heap上内存的地址想获得对应的bitmap地址就很简单了,不需要像tcmalloc似的查找,直接简单的右移和加法就能获得;同时呢,操作系统的demand paging会自动处理还没有使用到的bitmap。这里大家就明白了为啥Go用了那么大的虚拟内存(arena)并且知道为啥经常在内存不足的时候panic说申请到的内存不在范围了(因为内存不在bitmap所能映射的范围里,当然多个bitmap是可以解决这个问题的,不过目前还不支持);回到开始的那个问题,既然arena有个地址范围,判断一个uintptr是否可能是指针就是判断是否在这个范围里了。

这样的问题就来了。如果我有一个int32,他的内容恰巧在那个范围里,更碰巧的是如果把它当作指针,它恰巧指向一个大的数据结构,那么GC只能认为那个数据结构还在使用中。这样就造成了泄露。这个问题在32位/64位平台上都是存在的。但是在32位上问题更严重些,主要是32位表示的地址空间有768MB是Arena,也就是说一个均匀分布的uintptr是指针的概率是768/4096,这个远比64位系统的16GiB/(2^64B)的概率大得多。

Go 1.1不出意外的话会使用记录每个heap上分配的对象的类型的方式来几乎完整地解决这个问题;说几乎完整是因为,堆栈上的数据还是没有类型的,所以这里面还是有前面说的问题的,只不过会影响会小很多了


鲜花

握手

雷人

路过

鸡蛋
该文章已有0人参与评论

请发表评论

全部评论

专题导读
上一篇:
1 Go 语言环境安装发布时间:2022-07-10
下一篇:
本地安装 A tour of Go中文版发布时间:2022-07-10
热门推荐
热门话题
阅读排行榜

扫描微信二维码

查看手机版网站

随时了解更新最新资讯

139-2527-9053

在线客服(服务时间 9:00~18:00)

在线QQ客服
地址:深圳市南山区西丽大学城创智工业园
电邮:jeky_zhao#qq.com
移动电话:139-2527-9053

Powered by 互联科技 X3.4© 2001-2213 极客世界.|Sitemap