Go Runtime
2021-07-15 11:54:54 0 举报
AI智能生成
Go Runtime 相关知识:调度、内存管理、GC,不断完善中。。。
作者其他创作
大纲/内容
调度
GM模型
模型结构
Machine、Mcache
Goroutine
缺点
全局调度锁问题
G的传递问题
Per-M的内存问题
思想:不断共享,减少切换成本
让多个Goroutine通过用户级别的上下文切换来共享内核线程的计算资源。
切换成本小,上下文切换只涉及3个寄存器
占用内存小,Goroutine栈空间最小2k
GPM模型
地鼠推车搬砖举例
砖块-G
小车-P
地鼠-M
模型结构
Process、Mcache
Machine
LRQ(256)/GRQ
G状态流转
_Gidle
_Grunnable
_Grunning
_Gsyscall
_Gwating
_Gdead
调度器
策略
work-stealing - 允许从GRQ或其他P的LRQ中获取G执行
hand off- P与M脱离
减少阻塞
原子、互斥量或者通道操作调用,切换阻塞G
网络IO,让netpoll去处理,切换阻塞G
系统调用,P与M脱离,让P与其他空闲M结合
Sleep调用,设置抢占标识,让别的G来抢占
调度流程
sysmon协程
运行间隔
初始为20us,运行1ms后逐渐翻倍,最终10ms运行一次;
抢占成功后,而恢复成20us
执行工作
打印调度信息
通知GC
归还内存
从netpoll中获取ready的协程
执行抢占
系统调用,P与M脱离
非系统调用,通知抢占
内存分配器
设计分配方法
线性分配
空闲链表分配
分配策略
首次分配
循环首次分配
最优适应
隔离适应(Go采用类似策略)
分级分配机制
借鉴了线程缓存分配(Thread-Caching Malloc,TCMalloc)的设计实现高速的内存分配
核心理念:使用多级缓存将对象根据大小分类,并按照类别实施不同的分配策略。
虚拟内存布局
线性内存(1.11前)
设计思想
内部实现
存在的问题
二维稀疏内存(1.11)
设计思想
好处
内存管理组件
内存管理的基本单元mspan
mspan之间形成双向链表结构
每个mspan 都管理 npages 个大小为 8KB 的页
以页为单位向堆申请内存,以对象为单位查找分配空间
67种跨度类spanClass
决定了mspan存储的对象大小和个数
每一个跨度类都会存储特定大小的对象并且包含特定数量的页数以及对象
存储类别ID 为 0 的特殊跨度类,它能够管理大于 32KB 的特殊对象
含有noscan 标记位,表示存储对象是否包含指针,方便后期垃圾回收
线程缓存mcache
同处理器P绑定,主要用来缓存用户程序申请的微小对象。无锁访问内存管理单元
每一个线程缓存都持有 67 * 2 个 mspan
初始化:初始化时是不包含 mspan 的
替换:只有当用户程序申请内存时才会从上一级组件获取新的 mspan 满足内存分配的需求。
内含三个字段组成了微对象分配器
只会用于分配非指针类型的内存
默认为 16 字节以下的对象申请和管理内存
中心缓存mcentral
访问中心缓存中的内存管理单元需要使用互斥锁
内含2个mSpanList
有空闲对象的未满 mspan 结构
没有空闲对象的满的 mspan
每个mcentral都是一种mspan的全局后备资源
mcache从mcentral获取mspan过程
页堆mheap
持有的 134 个mcentral
一个全局的结构体,统一管理堆上初始化的所有对象
内部采用二维矩阵 runtime.heapArena管理所有内存空间,内存可以是不连续的:
Linux 的 x86-64架构上,单个 Go 语言程序的内存上限也就是 256TB
从堆中申请内存的途径
处理器的页缓存 runtime.pageCache
全局的页分配器 runtime.pageAlloc
之间联系
中心缓存属于页堆,它会从操作系统中申请内存,会维护全局的内存基本单元,各个线程会通过中心缓存获取新的内存单元
内存分配策略
微对象 (0, 16B)
先使用微型分配器,再依次尝试线程缓存、中心缓存和堆分配内存;
小对象 [16B, 32KB]
依次尝试使用线程缓存、中心缓存和堆分配内存;
大对象 (32KB, +∞)
直接在堆上分配内存;
内存地址
地址空间状态
None
Reserved
Prepared
Ready
状态转换过程
其他
内存管理模块中一共包含 67 种跨度类
Linux 的 x86-64架构上,单个 Go 语言程序的内存上限也就是 256TB
采用类似 TCMalloc 的分配策略将对象根据大小分类,并设计多层级的组件提高内存分配器的性能。
垃圾回收器GC
0 条评论
下一页