Skip to Content
Go 语言内存分配

整体介绍

Golang 的内存分配机制是 Go 运行时系统的重要组成部分,设计目标是:高效、可扩展、低延迟。它在运行时使用了一套三层分配器架构mcachemcentralmheap,配合**垃圾回收器(GC)**一起工作。


一、整体架构(重点)

Go 的内存分配分为两个大类:

类型特点分配路径
小对象(<=32KB)使用 内存池 + 对象缓存 的方式mcache → mcentral → mheap
大对象(>32KB)直接从堆上分配直接使用 mheap

其中主要的组件如下:

组件作用
mcache每个 P 绑定的本地缓存,最快
mcentral跨线程共享缓存,中等速度
mheap操作操作系统内存,最慢

二、重要概念

P、M、G 模型

  • P(Processor):调度器,持有 mcache
  • M(Machine):真正的执行线程。
  • G(Goroutine):用户代码。

每个 P 对应一个 mcache,用于缓存小对象,加快分配速度。


三、分配流程(重点)

小对象(<=32KB)分配流程:

// 示例:make([]int, 10)
  1. 调用 runtime.newobject()runtime.mallocgc()
  2. 在当前 Pmcache 中找对应大小 class 的 span(object 块集合)
  3. 如果找到了可用对象,直接分配,更新 bitmap
  4. 如果 mcache 中没有空闲对象:
    • mcentral 获取新的 span
  5. 如果 mcentral 也没有可用 span:
    • mheap 获取新的 span,并返回给 mcentral
  6. mheap 无法满足时,从操作系统分配新的内存页(通过 sysAlloc

newobject() 本质就是调用了 mallocgc(),带上了一些参数(类型信息、是否需要 GC 跟踪等)

重点机制:

  • 大小分级(size class):将对象按大小分成约 67 个级别(8B 到 32KB)
  • Span:是一组相同大小对象的内存块集合

大对象(>32KB)分配流程:

  1. 直接向 mheap 请求 span
  2. 跳过 mcachemcentral
  3. 通常直接通过 sysAlloc 从操作系统申请内存页(类似 mmap

四、垃圾回收(GC)与内存回收

Go 使用 三色标记清除算法(concurrent mark & sweep)

阶段工作内容
STW 开始停止世界,准备标记
并发标记标记活动对象(灰 → 黑)
并发清除回收未标记对象(白)
STW 清理停止世界,清理并恢复运行

GC 如何影响内存分配?

  • GC 回收对象后,会将对应的 span 标记为可重用。
  • mcentral 会将清理后的 span 返回给 mcache
  • 整个过程尽量最小化 STW 时间,保证低延迟。

五、相关数据结构

名称描述
mcache每个 P 的本地缓存
mcentral跨 P 的全局缓存
mheap管理 Span 的堆
span固定大小的内存块集合
bitmapGC 用于追踪对象存活状态
arenaGo 向操作系统申请的大内存区块

🔍 六、调试和观察工具

工具用法
GODEBUG=gctrace=1打印 GC 日志
pprof性能分析,包括内存分析
runtime.ReadMemStats获取当前内存使用情况

总结(重点回顾)

核心流程:

mcache(P 本地) → mcentral(全局) → mheap(系统堆)

对象分级:

  • 小对象(≤ 32KB)使用 span 缓存快速分配
  • 大对象(> 32KB)走系统分配路径

性能优化重点:

  • 减少 GC 触发频率
  • 优化对象复用和生命周期
  • 合理控制内存占用

与 ChatGPT 的对话

Last updated on