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

Go内存分配

图解Go语言内存分配 - 知乎

go内置运行时,采用了自主管理,实现更好的内存使用模式,不需要每次内存分配都进行系统调用

采用TCMalloc算法:把内存分为多级管理,从而降低锁的粒度

将可用的堆内存采用二级分配的方式进行管理:

每个线程都会自行维护一个独立的内存池,内存分配时优先从内存池中分配,内存池不足时向全局内存池申请,避免对全局内存池的频繁竞争

在程序启动时,向操作系统申请一块内存
请添加图片描述
arena:堆区,go动态分配内存,把内存分割为8kb大小的页,一些页组合称为mspan

bitmap:标识 arena 中哪些地址保存了对象,并用4bit标志位标识对象是否包含指针,GC标记信息

​ 1个byte大小内存对应 arena区域中4个指针大小(指针大小8B)内存
bitmap的高地址指向arena的低地址,bitmap由高地址向低地址增长
请添加图片描述
span:存放mspan(arena 分割的页组合起来的内存管理基本单元)的指针,每个指针对应一页

​ 创建mspan时,按页填充对应的spans区域

内存管理单元

mspan:内存管理的基本单元,由一片连续的8kb的页组成的大块内存,一般是操作系统页大小的几倍,包含起始地址、mspan规格、页的数量等内容的双端链表

每个mspan按照自身的属性Size Class大小分割为若干个object,每个object存储一个对象

并且使用一个位图标记未使用的object

属性Size Class决定object大小,mspan只会分配给object尺寸大小接近的对象,对象大小小于object

每个Size Class两个mspan(span class)一个分配给含有指针的对象,一个分配个不含有指针对象
请添加图片描述

操作系统存储模型

多级模型 动态切换(因为数据的调用频率在实时发生变化)
请添加图片描述

虚拟内存与物理内存

在真实物理内存上的虚拟概念,用来代理,贴合用户使用视角

使用户(进程)觉得内存是连续的,而不是割裂的

实现内存“放大”的效果,虚拟内存可以由物理内存+磁盘补足,根据数据冷热进行动态置换

通过页表建立真实物理空间的映射关系

页表:聚合映射关系的数据结构
请添加图片描述

分页管理

虚拟内存中最小的操作单元:页

物理内存:帧

提高内存空间利用率(以页为粒度,外部碎片被替换为内部碎片,更相对可控)

提高内外交换效率

与虚拟内存机制呼应,建立虚拟地址到物理地址的映射关系

Golang内存模型

以空间换时间,一次缓存,多次复用

每次向操作系统多申请内存

堆mheap同样的思想:

对操作系统,用户进程中缓存的内存

对Go进程内部,堆是所有对象的内存起源

多级缓存,实现无/细锁化
请添加图片描述
mcentral 根据对象的大小从小到大排列等级(集合)

当分配内存给一个对象时,会根据其大小找到从属的等级,在对应的mcentral中尝试获取内存

mcache 每个处理器§单独的本地私有缓存,其中冗余每一种等级的内存空间

当尝试获取内存时,根据处理器,查看本地私有的mcache中是否有合适的空间使用,有则直接获取,无则访问mcentral,一级一级升级向上获取

多级规格,提高利用率
mcentral
请添加图片描述
page:go中有独立的内存存储单元,最小的存储单元 8KB

mspan:最小的管理单元,为page的整数倍,从8B到80KB分为67种不同的规格,分配对象时根据大小映射到不同规格的mspan,获取空间

隐藏的0级,处理更大的对象,上不封顶
请添加图片描述

mspan

属于mcentral的一个节点,根据span的不同等级有一个central实例,central存储的span个数是复数
请添加图片描述
stratAddr 起始地址 映射到Go语言中堆内存的一部分空间,也是虚拟内存中对应的地址

npages 页的页数,每个mspan中的页是连续的,可以根据起始地址+页数推导出,对应的内存区域
请添加图片描述
allocCache 基于bitmap辅助快速找到空闲内存块(块大小为对应等级下对象大小)

查找mspan中哪些页是空闲的,可以把对象分配到里面
请添加图片描述

type mspan struct {_    sys.NotInHeap// 标识前后节点的指针next *mspan     prev *mspan     // 起始地址startAddr uintptr// 包含页数,页是连续的npages    uintptr // 标识此前的位置(bit位)都已被占用freeindex uint16// 最多可存放多少个对象(会出现一页存放多个对象的情况)nelems uint16// 每个bit对应一个对象块,标识该块是否被占用allocCache uint64// 标识mspan等级,包含class和noscan信息spanclass spanClass......
}

请添加图片描述
bytes/obj:该大小规格的对象会从当前等级的mspan中获取空间,创建对象过程中,大小会向上取整为8B的整数倍,可以直接实现对象到mspan等级映射

bytes/span:该等级的mspan的总空间大小

object:最多可以new多少个对象

max waste:
请添加图片描述
请添加图片描述

// nocan 标识对象是否包含指针,在gc时是否需要展开标记
// 存在指针需要展开扫描形成完整的有向图
// 会将两类对象,划分给不同的span(同一等级下的不同span)
// 将class+nocan组装为uint8,形成完整的spanClass 标识
// 高7位表示span等级,最低为表示nocan信息
type spanClass uint8func makeSpanClass(sizeclass uint8, noscan bool) spanClass {return spanClass(sizeclass<<1) | spanClass(bool2int(noscan))
}func (sc spanClass) sizeclass() int8 {return int8(sc >> 1)
}func (sc spanClass) noscan() bool {return sc&1 != 0
}

mcache

每个P独有的缓存,交互无锁
请添加图片描述
alloc 将每种spanClass等级的mspan各缓存一个,总数为2*68

对象分配器 tiny allocator 处理小于16B对象的内存分配

type mcache struct {_ sys.NotInHeap// 微对象分配器相关tiny       uintptrtinyoffset uintptrtinyAllocs uintptr// mcache中缓存的mspan,每种各一个alloc [numSpanClasses]*mspan ......
}

mcentral中心缓存

请添加图片描述
每个central对应一个spanClass

会将mspan分为两个链表,有空间mspan链表partial和满空间mspan链表 full

type mcentral struct {_         sys.NotInHeap// 对应的spanClassspanclass spanClass// 有空位mspan集合// 数组长度为2,抗一轮GCpartial [2]spanSet // 无空位full    [2]spanSet
}

mheap全局堆缓存

对于Golang上层应用,堆是操作系统虚拟内存的抽象

堆内存中最小内存存储单元:页(8KB)

负责将连续页组装为mspan

全局内存基于bitMap标识使用情况,一个bit对应一页,0自由,1已被组装为mspan

通过heapArena聚合页,记录页到mspan的映射信息,维护页所属的mspan关系

建立空闲页基数树索引 radix tree index 快速寻找空闲页,获取至少在虚拟视角下连续的空闲页

mcentral 的持有者,持有所有spanClass下mcentral,作为自身缓存,mcentral是mheap更细粒度的缓存(以空间换时间的操作)

内存不够,向操作系统申请,单位:heapArena(64M)

type mheap struct {_ sys.NotInHeap// 堆的全局锁(进程维度)lock mutex// 空闲页分配器,底层由多棵基数树组成的索引,每棵树对应16GB内存空间pages pageAlloc // 记录所有mspan// 所有mspan都是由mheap,使用连续空闲页组装allspans []*mspan // heapAreana 数组 请求内存和映射关系// 64位系统下,二维数组容量为[1][2^22]// 每个heapArena大小64M// 理论上堆的上限为 2^22*64M = 256Tarenas [1 << arenaL1Bits]*[1 << arenaL2Bits]*heapArena// 多个mcentral,总数为spanClass 个数central [numSpanClasses]struct {mcentral mcentral// 用于内存地址对齐pad      [(cpu.CacheLinePadSize - unsafe.Sizeof(mcentral{})%cpu.CacheLinePadSize) % cpu.CacheLinePadSize]byte}......
}
http://www.dtcms.com/a/275819.html

相关文章:

  • linux系统mysql性能优化
  • 【Modern C++ Part9】Prefer-alias-declarations-to-typedefs
  • Opencv---深度学习开发
  • 云计算三大服务模式深度解析:IaaS、PaaS、SaaS
  • 【数据结构与算法】数据结构初阶:详解顺序表和链表(四)——单链表(下)
  • 【PTA数据结构 | C语言版】后缀表达式求值
  • Transforms
  • Spring(四) 关于AOP的源码解析与思考
  • 一文理解缓存的本质:分层架构、原理对比与实战精粹
  • 别再怕 JSON!5分钟带你轻松搞懂这个程序员的好帮手
  • 鸿蒙的NDK开发初级入门篇
  • RISC-V:开源芯浪潮下的技术突围与职业新赛道 (四) 产业应用全景扫描
  • (LeetCode 面试经典 150 题 ) 209. 长度最小的子数组(双指针)
  • Ntfs!LfsFlushLfcb函数分析之while的循环条件NextLbcb的确定和FirstLbcb->LbcbFlags的几种情况
  • docker-compose方式搭建lnmp环境——筑梦之路
  • 【android bluetooth 协议分析 07】【SDP详解 2】【SDP 初始化】
  • Operation Blackout 2025: Smoke Mirrors
  • Windows符号链接解决vscode和pycharm占用C盘空间太大的问题
  • NX二次开发——导入模型是常遇见的问题(导入模型原点的确定导入模型坐标的确定)
  • BERT:双向Transformer革命 | 重塑自然语言理解的预训练范式
  • 深入理解大语言模型:从核心技术到极简实现
  • 洛谷题解 | UVA1485 Permutation Counting
  • jenkins自动化部署前端vue+docker项目
  • 前端面试宝典---项目难点2-智能问答对话框采用虚拟列表动态渲染可视区域元素(10万+条数据)
  • 自动化运维工具jenkins问题
  • Ubuntu安装Jenkins
  • java堆的创建与基础代码解析(图文)
  • Classifier guidance与Classifier-free guidance的原理和公式推导
  • 深大计算机游戏开发实验三
  • 深度学习图像分类数据集—害虫识别分类