课程章节:9-5
课程讲师:Moody
课程内容:
▲对于整个内存的描述是mheap
▲mheap下面有2的22次方个heapArena,每个heapArena是64M
▲mheap维护了一个mcentral 中心索引,该索引是67+1+67+1 = 136 个mecentral,分别是有指针的67个不同跨度的mspan索引和67个没有指针,一个无指针0类型和一个有指针0类型,有指针的会被GC扫描,没有指针的通常是常量这些不需要GC扫描的。
▲一个mecentral只负责一个规格span,规格类型记录在mcentral的spanClass字段中。mcentral维护着两个双向链表,nonempty表示链表里还有空闲的mspan待分配。empty表示这条链表里的mspan都被分配了object。mcache从mcentrl中获取和归还span流程如下:
获取时候先加锁,先从nonempty中获取一个没有分配使用的span,将其从nonempty中删除,并将span加入empty链表,mcache获取之后释放锁。
归还时候先加锁,先将span加入nonempty链表中,并从empty链表中删除,最后释放锁。
type mcentral struct { lock mutex // 锁,由于每个p关联的mcache都可能会向mcentral申请空闲的span,所以需要加锁 spanclass spanClass // mcentral负责的span规格 nonempty mSpanList // 空闲span列表 empty mSpanList // 已经使用的span列表 nmalloc uint64 // mcentral已分配的span计数 }
★go内存申请过程
使用heapArena向操作系统申请内存
使用heapArena的时候,是一mspan为单位进行申请的
heapArena的相关信息(地址索引)是保存在mheap里面的
用户程序使用的内存会向mheap进行申请,每次申请是申请一组内存,以mspan为单位,防止碎片化
申请的内存不会被程序直接使用,而是由mcental建立起中心索引
用户的程序在协程所在的线程中执行的时候,并不是直接调取mecentral找符合size的mspan,因为mecentral使用的时候是有锁的,并发情况下效率低下,而是把一部分mecentral缓存到P线程本地,使用的时候直接找缓存mcache。如果mcache不够用了,会去mcental里交换
★线程获取新内存管理单元
调用runtime.mcentral.partialSwept 从清理过、包含空闲内存的spanSet结构体中查找可用的内存
partialUnswept 从未被清理过、包含空闲内存的spanSet里面朝招可用内存单元
fullUnswept从未被清理过的、不包含空闲空间的spanSet上获取内存管理单元,并用sweep进行清理
如果经过上诉三个步骤都没有找到可用内存,就会调用grow申请新的内存
更新allocCache、allocBits