手记

【金秋打卡】第3天 Go的内存模型和mcentral

课程名称深入Go底层原理,重写Redis中间件实战

课程章节: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内存申请过程

  1. 使用heapArena向操作系统申请内存

  2. 使用heapArena的时候,是一mspan为单位进行申请的

  3. heapArena的相关信息(地址索引)是保存在mheap里面的

  4. 用户程序使用的内存会向mheap进行申请,每次申请是申请一组内存,以mspan为单位,防止碎片化

  5. 申请的内存不会被程序直接使用,而是由mcental建立起中心索引

  6. 用户的程序在协程所在的线程中执行的时候,并不是直接调取mecentral找符合size的mspan,因为mecentral使用的时候是有锁的,并发情况下效率低下,而是把一部分mecentral缓存到P线程本地,使用的时候直接找缓存mcache。如果mcache不够用了,会去mcental里交换

★线程获取新内存管理单元

  1. 调用runtime.mcentral.partialSwept 从清理过包含空闲内存的spanSet结构体中查找可用的内存

  2. partialUnswept 从未被清理过包含空闲内存的spanSet里面朝招可用内存单元

  3. fullUnswept从未被清理过的不包含空闲空间的spanSet上获取内存管理单元,并用sweep进行清理

  4. 如果经过上诉三个步骤都没有找到可用内存,就会调用grow申请新的内存

  5. 更新allocCache、allocBits




0人推荐
随时随地看视频
慕课网APP