专栏首页Go语言指北Go高阶指南14,内存的分配原理

Go高阶指南14,内存的分配原理

Go 中实现的内存分配器,简单的说就是维护了一大块全局内存,每个线程(Go 中的 P)维护一小块的私有内存,当私有内存不足时再向全局申请。内存分配与 GC(垃圾回收)有密切关系。

概念

为了方便自主管理内存,做法便是先向系统申请一块内存,然后将内存切割成小块,通过一定的内存分配算法管理内存。以64位系统为例,Golang 程序启动时会向系统申请的内存如下图所示:

预申请的内存划分为 spans、bitmap、arena 三部分

arena 即所谓的堆区,应用中需要的内存从这里分配,spans 和 bitmaps 是用来管理 arena 的。

  • arena :大小为 512 G,为了方便管理把arena区域划分成一个个的page,每个 page 为 8KB,一共有 512GB/8KB 个页;
  • spans :区域存放 span 的指针,每个指针对应一个 page,所以 span区域的大小为(512GB/8KB)*指针大小8byte = 512M
  • bitmap :区域大小也是通过 arena 计算出来,不过主要用于GC。

span

span是用于管理 arena 页的关键数据结构,每个 span 中包含1个或多个连续页,为了满足小对象分配,span中的一页会划分更小的粒度,而对于大对象比如超过页大小,则通过多页实现。

内存分配过程

针对待分配对象的大小不同有不同的分配逻辑:

  1. 申请一块较大的虚拟内存空间,用于内存分配及管理
  • 当空间不足时,向系统申请一块较大的内存,如100KB或者1MB
  • 申请到的内存块按特定的size,被分割成多种小块内存(go:_NumSizeClasses = 67),并用链表管理。创建对象时,按照对象大小,从空闲链表中查找到最适合的内存块。
  1. 销毁对象时,将对应的内存块返还空闲链表中以复用。
  2. 空闲内存达到最大值时,返还操作系统。

管理组件

go将内存分为三个层级,协程私有内存,全局内存,整体内存叶管理,也因此有这三个层级的内存管理工具。

  • mspan: mspan 并不直接拥有内存空间,它负责管理起始地址为 startAddr、级别(预分配页的个数)为 sizeclass 的连续地址空间。
  • mcache: Per-P私有cache,用于实现无锁的 object 分配,每个 mcache 有大小为67的 mspan 数组,存储不同级别大小的 mspan。
  • mcentral: 全局内存,为各个 cache 提供按大小划分好的 mspan,mcentral有个关键方法 cacheSpan(),它是整个分配的核心算法
  • mheap 是真实拥有虚拟地址的结构,page 管理,内存不足时向系统申请。

总结

  1. Golang 程序启动时申请一大块内存,并划分成spans、bitmap、arena 区域
  2. aren a区域按页划分成一个个小块
  3. span 管理一个或多个页
  4. mcentral 管理多个 span 供线程申请使用
  5. mcache 作为线程私有资源,资源来源于 mcentral

【侵权删】文中涉及资料及图片来源:

https://studygolang.com/articles/21911?fr=sidebar

《go专家编程》

百度图片


有什么问题,可以公众号内回复或加我微信交流。

本文分享自微信公众号 - 微客鸟窝(gophpython),作者:有码无尘

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2021-09-05

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • Go高阶指南04,struct 实现原理

    Go 语言中没有像类的概念,但是可以通过结构体 struct实现面向对象编程。struct 结构体的一些基础使用可以看下之前的文章--结构体和接口的使用,传送门...

    微客鸟窝
  • Go高阶指南05,iota 实现原理

    我们知道,iota 常用于 const 表达式中,它的值是从 0 开始,每增加一行,iota 值 +1。

    微客鸟窝
  • Go高阶指南06,string 实现原理

    源代码中 src/builtin/builtin.go string 的描述如下:

    微客鸟窝
  • Go高阶指南09,select 实现原理

    select 是 GO 语言中用来提供 IO 复用的机制,它可以检测多个 chan 是否 ready(可读/可写)。

    微客鸟窝
  • Go高阶指南02,slice 实现原理

    slice 切片,因为其可以方便的进行扩容、传递等,在实际应用中比数组更加灵活。切片的一些基础使用可以看下之前的文章,传送门。

    微客鸟窝
  • Go高阶指南10,一文搞懂 range 实现原理

    range 是 Go 语言用来遍历的一种方式,它可以操作数组、切片、map、channel 等。

    微客鸟窝
  • Go高阶指南07,一文搞懂 defer 实现原理

    defer 语句用于延迟函数的调用,使用 defer 关键字修饰一个函数,会将这个函数压入栈中,当函数返回时,再把栈中函数取出执行。

    微客鸟窝
  • [译] Go语言内存管理与分配

    Go程序的内存从申请阶段到不再使用后的释放阶段都由Go标准库自动管理。尽管管理工作不需要开发者参与,但是Go对内存管理的底层实现做了非常好的优化,里面充满了有意...

    猿哥
  • 图解Go内存管理器的内存分配策略

    在Go语言里,从内存的分配到不再使用后内存的回收等等这些内存管理工作都是由Go在底层完成的。虽然开发者在写代码时不必过度关心内存从分配到回收这个过程,但是Go的...

    KevinYan
  • Github开源免费编程书籍

    时见疏星
  • 面向DevSecOps的编码安全指南| JavaScript篇

    近年来,无论是DevSecOps,还是Google SRE的可靠和安全性理念,都提倡“安全需要每个工程师的参与”。其中涉及的“安全左移”理念也再次被推向前台,获...

    腾讯安全应急响应中心
  • Golang学习笔记之方法(method)

    一个方法只是一个函数,它有一个特殊的接收者(receiver)类型,该接收者放在 func 关键字和函数名之间。接收者可以是结构体类型或非结构体类型。可以在方法...

    李海彬
  • 聊聊阿秀过去三年间做的最正确的一件事 | 快来薅羊毛

    我买的大部分是技术书,也有一些非技术书,比如《明朝那些事儿》、《平凡的世界》之类的。

    拓跋阿秀
  • 使用Terraform配置Linode环境

    基础架构代码(IaC)是一种软件,使开发人员能够使用高级配置语法构建,管理和配置计算环境。一些好处包括能够实施DevOps最佳实践,流程自动化以及使用版本控制系...

    GongAo啊_
  • 适合 Go 新手学习的开源项目——在 GitHub 学编程

    故事要从 2007 年说起。因为受够了 C++ 煎熬的 Google 首席软件工程师 Rob Pike 召集 Robert Griesemer 和 Ken Th...

    HelloGitHub
  • 安全左移理念,鹅厂 DevSecOps 如何实践?

    ? 作者:yuyangzhou、dexyfruan,腾讯 TEG 应用运维安全工程师 引子 随着 DevOps 模式的落地,快字当头。研效提速也意味着出现安...

    腾讯技术工程官方号
  • Go开发者路线图2019,请收下这份指南

    Go是Google开发的一种静态、强类型、编译型、并发型,并具有垃圾回收功能的类C编程语言。2009以开源项目的形式发布,2012年发布1.0稳定版本,距今已经...

    AI科技大本营
  • Go 语言学习路线来啦

    时不时的有人问我一些关于 Go 语言学习路线、学习资源方面的问题,这篇文章就来详细说一说。借此希望给那些正在学习,或是想学习 Go 语言的朋友一些帮助。

    roseduan
  • Go - 基于逃逸分析来提升程序性能

    因为我们想要提升程序性能,通过逃逸分析我们能够知道变量是分配到堆上还是栈上,如果分配到栈上,内存的分配和释放都是由编译器进行管理,分配和释放的速度非常快,如果分...

    新亮

扫码关注云+社区

领取腾讯云代金券