第 12 章 内存分配器
内存分配被普遍认为要么是一个已经解决的问题,要么是一个无法解决的问题。Memory allocation is widely considered to be either a solved problem or an insoluble one.
-- Paul R. Wilson et al., "Dynamic Storage Allocation: A Survey and Critical Review", 1995
这句话出自 Wilson 等人 1995 年那篇综述的摘要。综述接着指出,以往的理论分析与实验评测大多假设程序的请求随机而相互独立,真实程序的行为却有重要的规律,分配器只有利用这些规律,才能在实践中表现良好。Go
的分配器还要多面对一层约束:Go 没有显式的 free,对象何时可以重用由垃圾回收器决定,回收器又不移动对象,因此分配器必须与回收器一同设计,碎片也只能在分配时加以控制。
12.1 讨论分配器需要兼顾的目标、它从 TCMalloc 继承的结构,以及尺寸类与按大小、类型分流的设计。12.2 介绍 mspan、mcache、mcentral、mheap 等组件及其协作。12.3
讨论启动时的初始化、地址空间的划分,以及内存的预留、映射与提交。12.4
至 12.6 依次讨论大对象、小对象与微对象的分配路径。12.7
讨论以位图与基数树管理页的页分配器,以及向操作系统归还物理内存的 scavenger。12.8
讨论运行时如何统计内存,并经由 runtime.ReadMemStats、runtime/metrics 与堆剖面对外报告。12.9
按时间回顾分配器的演进。回收器的实现见第 13 章,goroutine
执行栈的分配见第 14 章。