go内存管理
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,作用也类似,不再赘述。