这是我参与「第三届青训营 -后端场」笔记创作活动的的第14篇笔记
😆在这里,我对今天所新学到的Golang内存管理及优化做了一次总结
😜Golang的其他知识在哪里找呢,那你就问对了
👨💻Golang基础复习 - 掘金 (juejin.cn) 在这里我总结了一些这篇文章没有提到的一些知识
😊如果有小伙伴能想到更多知识,欢迎大家在评论区留言,那么我们就开始吧
👩💻👨💻哟西,一个棕~
😎😎😎我是小小分割线
Golang中内存分配
分块
首先会提前将内存分成多个块
分块步骤:
-
调用系统调用mmap()向OS申请一大块内存
-
将内存划分成大块,称作mspan
-
将大块继续划分成特定大小的小块,用于对象分配
noscan mspan:分配不包含指针的对象 ---- GC不需要扫描
scan mspan: 分配包含指针的对象 ------ GC需要扫描
也就是说
noscan没有指针指向其他对象,只有它自己
而比如链表,有指针指向其他的对象
对象分配:根据对象大小选择一个最合适的块返回
缓存
golang内存分配借鉴了TCMalloc:Thread caching
对内存做了很多级不同的缓存,用来加快速度
在Golang中我们的程序都是写在协程上的,我们每一个p都包含一个mcache用来快速分配内存到绑定它的g上
-
mchache管理了一组的mspan
-
当mcache中的mspan分配完毕后会向mcentral中申请带有未分配块的mspan
-
当mspan中没有分配对象也不会立刻释放还给os,而是会缓存在mcentral中
Golang内存管理优化
面对的问题
-
对象分配非常高频 (在线上,每秒常常都会分配GB级别的内存)
-
小对象占比是比较高的
-
Go内存分配比较耗时
分配路径长: g -> m -> p -> mcache -> mspan -> memory block -> return pointer
字节跳动的优化方案
Balanced GC
每个g都绑定一块大内存空间(1kb),称作:goroutine allocation buffer(GAB)
-
GAB用于noscan类型的小对象的分配: <128 B
-
使用三个指针维护GAB:base,end,top
-
Bump pointer(指针碰撞) 风格对象分配
由于每个g都绑定独立的GAB,所以无须和其他分配请求互斥
分配动作简单高效
只要我们剩下的内存足够,为我们就移动top指针,将内存返回出去即可
就不必走之前的那么长的路了,直接移动top指针,然后将内存空间返回出去即可
GAB相对于Golang的内存管理来说就是一个大对象
本质就是将多个小对象的分配合并成一个大对象的分配
出现的问题:
只要GAB中有对象,无论多大GAB都会存活不会被释放并耗费1KB
方案:
当GAB总大小超过一定阈值时,将GAB中给存活的对象复制到另一个分配的GAB
原先的GAB会被释放,避免内存泄漏
本质是用Copying GC算法管理小对象
以上就是我对今天所学到的Golang内存管理及优化的总结
😎😎😎又是我,我还是小小分割线
都用心看到这里了,那就求个赞吧😘
🥳🥳🥳如果小伙伴有其他的小知识,一定不要忘了在评论区讨论哟,多多讨论,生态才会越来越好