GO内存管理

What ?

内存的分配,回收,释放的过程。go的内存分配基于TCMalloc的原理实现。通常我们说内存管理指的是堆(Heap)内存管理,因为栈(Stack)不需要我们关心。

关于tcmalloc

tcmalloc是一个内存管理库,全称Thread-Cache Malloc,理解为带缓存的内存管理,其实就是为每一个线程创建一个缓存,每次为线程分配内存的时候,首先判断其大小,较小的内存块(小于32K)会首先从缓存中获取,较大的才会从Head内存中分配,这样可以减少系统调用,提高效率。

三个关于tcmalloc的重要概念
  • ThreadCache:每个线程创建的时候会为其分配包含多个内存块的链表,这些内存块大小相同,你也可以理解为其实链表是对内存块按照大小进行分类。每次申请内存的时候,当申请的内存小于32k的时候,就在ThredCache选择合适的链表,然后在链表上选择空闲的内存块分配。

    1
    2
    - 为线程分配ThreadCache的时候,进行一次系统调用,后续从ThreadCache上面分配内存的时候不再需要系统调用过程,极大提高了效率。
    - ThreadChahe是线程安全的,因为它为某个线程所独有,不会产生竞争。
  • CentralCache:粗暴翻译就是”中央缓存”,其实是有点那个意思。它是进程级别的,同一进程所有线程共享。CentralCache本质上也是由空闲内存块组成的链表,当ThreadCache上空闲内存块不足的时候,CentralCache会分配给它一些;当ThredCache上面空闲的内存块过多的时,会将自身的空闲内存块返还给CentralCache。

    1
    - CentralCache是同一进程的线程共享的,所以会产生竞争,操作的时候需要添加锁。
  • PageHead:其实是堆内存的抽象,也是由若干链表组成,每个链表包含多个Span,每个Span其实使用多个Page组成。当CentralCache不足的时候,会从PageHead中获取,PageHead会将Span分成若干个内存块,放到CentralCache中。当CentralCache空闲内存太多时,会将一部分返还给PageHeap。

    1
    - PageHeap会产生多个CentralCache竞争,所以也是需要添加锁。

TCMalloc内存分配
  • 小对象直接从ThredCache中分配。
  • 中等对象从PageHead中选择合适数量的Span进行分配。
  • 大对象则从lagre span set分配。

GO的内存管理

GO内存管理原理是基于TCMalloc基础,GO内存管理中与之对应的三个重要组成部分包括:

MHeap

对内存的抽象依照Span Class对Span进行归类,形成树形结构。当需要分配的内存大于32K就在Mheap上面分配,首先根据申请内存的大小size得到Class szie, 进而根据Class size得到Span class, 最后根据Span class得到内存快Span。

MCache

与TCMalloc对应的ThreadCache, 但是与ThredCache与线程绑定不同,Mcache是与逻辑处理器P绑定,因为每一个Goroutine是运行在Processor,当需要申请的内存小于32K的时候,直接从MCache中得到,而不用进过系统调用,也不与其他Goroutine产生竞争。

MCentral

与TCMalloc对应的CentralCache,作用也类似,不再赘述。