当前位置: 首页 > 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.lryc.cn/news/586205.html

相关文章:

  • python excel处理
  • 【世纪龙科技】新能源汽车结构原理体感教学软件-比亚迪E5
  • Windows 用户账户控制(UAC)绕过漏洞
  • 单细胞分析教程 | (二)标准化、特征选择、降为、聚类及可视化
  • 力扣-24.两两交换链表中的节点
  • 7. 负载均衡:流量调度引擎
  • STM32--USART串口通信的应用(第一节串口通信的概念)
  • stack和queue的使用和模拟实现以及了解deque
  • Kafka——聊聊Kafka的版本号
  • React 组件中怎么做事件代理?它的原理是什么?
  • 【6.1.0 漫画数据库技术选型】
  • LRU缓存机制完全实战:链表的工程落地与面试通关
  • 复现永恒之蓝
  • 网络配置综合实验全攻略(对之前学习的总结)
  • 脉冲神经网络膜电位泄漏系数学习:开启时空动态特征提取的新篇章
  • docker配置
  • 【android bluetooth 协议分析 07】【SDP详解 2】【SDP 初始化】
  • 使用FastAdmin框架开发二
  • 算法魅力-BFS解决最短路问题
  • 【Elasticsearch】function_score与rescore
  • MS Azure Eventhub 发送 AD log 到cribl
  • 定长子串中元音的最大数目
  • PyQt5布局管理(QBoxLayout(框布局))
  • OSPFv3-一二类LSA
  • Java 之字符串 --- String 类
  • 机器学习(ML)、深度学习(DL)、强化学习(RL)关系和区别
  • 箭头函数(Arrow Functions)和普通函数(Regular Functions)
  • 虚拟现实的镜廊:当技术成为存在之茧
  • 云端docker小知识
  • Java 大视界:基于 Java 的大数据可视化在智慧城市能源消耗动态监测与优化决策中的应用(2025 实战全景)