Golang内存管理及优化 | 青训营笔记

327 阅读2分钟

这是我参与「第三届青训营 -后端场」笔记创作活动的的第14篇笔记

😆在这里,我对今天所新学到的Golang内存管理及优化做了一次总结

😜Golang的其他知识在哪里找呢,那你就问对了

👨‍💻Golang基础复习 - 掘金 (juejin.cn) 在这里我总结了一些这篇文章没有提到的一些知识

😊如果有小伙伴能想到更多知识,欢迎大家在评论区留言,那么我们就开始吧

👩‍💻👨‍💻哟西,一个棕~

😎😎😎我是小小分割线

Golang中内存分配

分块

首先会提前将内存分成多个块

分块步骤:

  1. 调用系统调用mmap()向OS申请一大块内存

  2. 将内存划分成大块,称作mspan

  3. 将大块继续划分成特定大小的小块,用于对象分配

image.png

noscan mspan:分配不包含指针的对象 ---- GC不需要扫描

scan mspan:  分配包含指针的对象 ------ GC需要扫描

也就是说

noscan没有指针指向其他对象,只有它自己

而比如链表,有指针指向其他的对象

对象分配:根据对象大小选择一个最合适的块返回

缓存

golang内存分配借鉴了TCMalloc:Thread caching

对内存做了很多级不同的缓存,用来加快速度

在Golang中我们的程序都是写在协程上的,我们每一个p都包含一个mcache用来快速分配内存到绑定它的g

image.png

  • 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 image.png

  • Bump pointer(指针碰撞) 风格对象分配

    由于每个g都绑定独立的GAB,所以无须和其他分配请求互斥

    分配动作简单高效

image.png

只要我们剩下的内存足够,为我们就移动top指针,将内存返回出去即可

就不必走之前的那么长的路了,直接移动top指针,然后将内存空间返回出去即可


GAB相对于Golang的内存管理来说就是一个大对象

image.png

本质就是将多个小对象的分配合并成一个大对象的分配

出现的问题:

只要GAB中有对象,无论多大GAB都会存活不会被释放并耗费1KB

方案:

当GAB总大小超过一定阈值时,将GAB中给存活的对象复制到另一个分配的GAB

原先的GAB会被释放,避免内存泄漏

image.png

本质是用Copying GC算法管理小对象


以上就是我对今天所学到的Golang内存管理及优化的总结

😎😎😎又是我,我还是小小分割线

都用心看到这里了,那就求个赞吧😘

🥳🥳🥳如果小伙伴有其他的小知识,一定不要忘了在评论区讨论哟,多多讨论,生态才会越来越好