当前位置: 首页 > news >正文

深入 Go 底层原理(五):内存分配机制

1. 引言

Go 语言的性能不仅得益于其高效的并发调度,还得益于其精心设计的内存分配器。Go 的内存分配器借鉴了 Google 自家的 TCMalloc (Thread-Caching Malloc) 思想,旨在实现高并发场景下的快速、低锁竞争的内存分配。

本文将深入 Go 的内存管理,揭示其分层式的内存分配架构。

2. Go 内存管理的宏观视图

Go 程序在启动时,会向操作系统申请一大块内存,并自行进行管理,避免了频繁的系统调用。这块内存被组织成一个多层级的结构,以优化不同大小对象的分配效率。

Go 的内存管理可以分为两个主要部分:

  1. 栈 (Stack) 分配: 用于管理 Goroutine 的函数调用栈。栈内存由 Goroutine 自行管理,分配和回收都非常快(通过移动栈指针),且不涉及 GC。

  2. 堆 (Heap) 分配: 用于管理程序动态创建的对象,是本文的重点。堆内存由 Go 的内存分配器和垃圾回收器共同管理。

3. 堆内存分配的核心组件

Go 的堆内存分配器是一个分层结构,主要由 mheap, mcentral, mcachemspan 构成。

  • mspan (Memory Span)

    • 定义:是内存管理的基本单位。一个 mspan 是由 runtime 管理的一块连续的、页对齐的内存(Go 中一页为 8KB)。

    • 属性:每个 mspan 都被划分为特定大小规格 (Size Class) 的小块,用于存放相同大小的对象。例如,一个 mspan 可能专门用于存放 16 字节的对象。Go 预定义了约 70 个不同的 Size Class。

  • mcache (Memory Cache)

    • 定义:一个与 P (Processor) 绑定的、线程私有的内存缓存。每个 P 都有一个自己的 mcache

    • 职责:为当前 P 上的 Goroutine 提供无锁的、快速的小对象内存分配。mcache 中包含一个 mspan 数组,每个 mspan 对应一种 Size Class。

    • 特点:因为 mcache 是 P 私有的,所以当 Goroutine 需要分配小对象时,可以直接从对应的 mcache 中获取,无需加锁,效率极高。

  • mcentral (Central Memory)

    • 定义:一个全局的、所有 P 共享的 mspan 缓存。

    • 职责:为所有 mcache 提供 mspan 资源。mcentral 按 Size Class 对 mspan 进行分组管理,每个 Size Class 都有一个 mspan 链表。

    • 特点:当一个 mcache 中的某个 Size Class 的 mspan 被用完时,它会向 mcentral 申请一个新的 mspan。这个过程需要加锁。反之,当 mcachemspan 有大量空闲时,也会归还给 mcentral

  • mheap (Memory Heap)

    • 定义:堆内存的最高管理者,持有从操作系统申请来的所有内存。

    • 职责:管理大量的 mspan。当 mcentral 缺少 mspan 时,会向 mheap 申请。mheap 会从其管理的页中划分出一块,组成一个新的 mspan 交给 mcentral

    • 特点:如果 mheap 自身内存不足,它会通过系统调用(如 mmap)向操作系统申请更多内存(通常以 Arena 为单位,64MB on 64-bit systems)。

4. 内存分配流程

根据对象的大小,分配流程有所不同:

  • 小对象分配 (<= 32KB)

    1. Goroutine 请求分配内存。

    2. 计算对象所需的大小规格 (Size Class)。

    3. 从当前 P 绑定的 mcache 中,找到对应 Size Class 的 mspan 链表。

    4. mspan 中获取一个空闲的小块内存。此过程无锁

    5. 如果 mcachemspan 没有空闲块,mcache 会向 mcentral 申请一个新的、可用的 mspan此过程需要加锁

    6. 如果 mcentral 也没有可用的 mspan,它会向 mheap 申请。

    7. 如果 mheap 也没有,它会向操作系统申请新内存。

  • 大对象分配 (> 32KB)

    • 对于大对象,分配器会绕过 mcachemcentral,直接由 mheap 进行分配。mheap 会寻找能容纳该对象的最佳 mspan

5. 总结

Go 的内存分配器通过 mcache-mcentral-mheap 的三级架构,实现了高效的内存管理。

  • mcache:通过 P 私有缓存,实现了小对象的无锁快速分配,这是其高性能的关键。

  • mcentral:作为中间协调者,平衡了所有 mcache 的资源需求。

  • mheap:作为最终的资源来源,统一管理所有堆内存。

这种设计,在保证高并发性能的同时,也有效地减少了内存碎片。

http://www.lryc.cn/news/607915.html

相关文章:

  • 操作系统-lecture5(线程)
  • Vue3核心语法基础
  • 【大模型入门】3.从头实现GPT模型以生成文本
  • 相对路径 绝对路径
  • UniappDay07
  • sqli-labs:Less-19关卡详细解析
  • Qt 槽函数被执行多次,并且使用Qt::UniqueConnection无效【已解决】
  • 24黑马SpringCloud的Docker本地目录挂载出现相关问题解决
  • Tushare对接OpenBB分析A股与港股市场
  • 解锁智能油脂润滑系统:加速度与温振传感器选型协同攻略
  • 深度学习核心:卷积神经网络 - 原理、实现及在医学影像领域的应用
  • 【Java】在一个前台界面中动态展示多个数据表的字段及数据
  • 定制开发开源AI智能名片S2B2C商城小程序的特点、应用与发展研究
  • 自进化智能体综述:通往人工超级智能之路
  • SpringBoot IOC
  • C++之vector类的代码及其逻辑详解 (中)
  • 【自动化运维神器Ansible】YAML语法详解:Ansible Playbook的基石
  • vue引入阿里巴巴矢量图库的方式
  • Kotlin协程极简教程:5分钟学完关键知识点
  • docker desktop入门(docker桌面版)(提示wsl版本太低解决办法)
  • 【MySQL】增删改查操作 —— CRUD
  • Elasticsearch 混合检索一句 `retriever.rrf`,把语义召回与关键词召回融合到极致
  • MySqL(加餐)
  • 在 AKS 中运行 Azure DevOps 私有代理-1
  • Cursor 与 VS Code 与 GitHub Copilot 的全面比较
  • 字节Seed发布扩散语言模型,推理速度达2146 tokens/s,比同规模自回归快5.4倍
  • [spring6: 分布式追踪]-实战
  • AI赋能测试:技术变革与应用展望
  • 在ChinaJoy ,Soul发布“莫比乌斯·第三弹”ChinaJoy特别款
  • 深入 Go 底层原理(十二):map 的实现与哈希冲突