接上篇:[ https://blog.csdn.net/robertkun/article/details/80140594 ] 在真正进入内存分配过程之前,还需要了解一下整个内存分配器是如何创建的以及初始化成什么样子。完成内存分配器创建初始化的函数是runtime·mallocinit,看一下简化的源码:
void runtime·mallocinit(void) { // 创建mheap对象,这个是直接从操作系统分配内存。 // heap是全局的,所有线程共享,一个Go进程里只有一个heap。 if((runtime·mheap = runtime·SysAlloc(sizeof(*runtime·mheap))) == nil) runtime·throw("runtime: cannot allocate heap metadata"); // 64位平台,申请一大块内存地址保留区,后续所有page的申请都会从这个地址区里分配。 // 这个区就是结构图中的arena。 if(sizeof(void*) == 8 && (limit == 0 || limit > (1<<30))) { arena_size = MaxMem; bitmap_size = arena_size / (sizeof(void*)*8/4); p = runtime·SysReserve((void*)(0x00c0ULL<<32), bitmap_size + arena_size); } // 初始化好heap的arena以及bitmap。 runtime·mheap->bitmap = p; runtime·mheap->arena_start = p + bitmap_size; runtime·mheap->arena_used = runtime·mheap->arena_start; runtime·mheap->arena_end = runtime·mheap->arena_start + arena_size; // 初始化heap的其他内部结构,如:spanalloc、cacachealloc都FixAlloc的初始化, // free、large字段都是挂载维护span的双向循环链表。 runtime·MHeap_Init(runtime·mheap, runtime·SysAlloc); // 从heap的cachealloc从分配MCache,挂在一个线程上。 m->mcache = runtime·allocmcache(); }初始化过程主要是在折腾mcache和mheap两个部分,而mcentral在实际逻辑中是属于mheap的子模块,所以初始化过程就没明确的体现出来,这和我绘制的结构图由两大块构造相对应。
heap是所有底层线程共享的;而cache是每个线程都分别拥有一个,是独享的。
在64位平台,heap从操作系统申请的内存地址保留区只有136G,其中bitmap需要8G空间,因此真正可申请的内存就是128G。当然128G在绝大多数情况都是够用的,但我所知道的还是有个别特殊应用的单机内存是超过128G的。
转自: [ http://skoo.me/go/2013/10/13/go-memory-manage-system-alloc ]
