大家一起学Golang——Go runtime内存分配

大家一起学Golang——Go runtime内存分配

go runtime内存分配

摒弃传统内存分配方式,使用自主管理,不需要每次系统调用分配内存,TCMalloc算法进行内存分配。

基本策略:

  1. 每次从操作系统申请大的内存,减少系统的调用
  2. 将申请的大内存按照固定的大小进行划分,并以链表的形式连起来
  3. 为对象分配内存时,需要从合适大小的链表取一块内存
  4. 回收对象时,将小块内存重新加到链表中,以便回收利用,提高利用率
  5. 如果闲置的内存增多,会尝试将部分内存归还操作系统,降低整体开销

内存管理单元:

  1. span 面向内存管理,由多个连续页(page 8kb大小)组成的大块内存
  2. object 面向对象分配,将span切成多个小块,每小块可以存储对象
    在这里插入图片描述
  • arena区域
    就是所谓的堆区,很多个8kb的页,一些页组合称为mspan
  • bitmap区域
    标识arena哪些区域地址保存了对象,并用4bit地址保存对象是否包含指针和GC标记
  • spans区域
    用来存放mspan指针,对应到每一个页page,spans区域大小512GB/8KB*8B=512MB

内存管理组件:

heap --> central --> cache

  • cache
    每个工作线程绑定1个mcahce,1个mcache管理n个mspan的空间
  • central
    central为所有的mcache提供切分好的mspan的资源
    当mcache从mcentral中申请一个page为8k大小,然后按照相同规格进行分割mspan,在object中进行使用。
  • heap
    管理闲置的span, mheap对象来进行管理堆内存,mcentral没有空间的mspan时,向mheap申请,mheap没有,则mheap向操作系统申请。mheap主要用于大对象的内存分配,管理未分割的mspan。mcentral来切割成小对象。

对于go运行时内存的分配的知识点,一般开发人员了解上述内容就差不多了。Go内存分配源码涉及链表结构,要理解每个部分的层级关系。更详细可参见 TCMallo解密 这个可是相当的详细~~

内存分配总结:

Go在程序启动时,会向操作系统申请⼀大块内存,然后自⾏管理。 Go内存管理的基本单元是mspan,它由若⼲个page页组成,每mspan可以分配特定⼤小的object。 mcache, mcentral, mheap是Go内存管理理的三⼤组件,层递进。mcache管理线程在本地缓存的mspan;mcentral管理全局的mspan供所有线程使用;mheap管理Go的所有动态分配内存。 一般小对象通过mspan分配内存,⼤对象则直接由mheap分配内存。