堆内存管理

堆内存分类
1 堆内存分为64M大小的arena,64*1024=65536
65536/8=8192 即每个arene分成8192个page。每个page为8kb

go在管理内存是,把内存划分成大小不同的67钟规格,最小8字节 最大32k字节

go把每个arena划分成大小不同的span,每个span包含一组连续的page
他们的关系是 堆内存>span>page>内存块
全局Span管理 mheap ,mheap.central
mheap:
//path: /usr/local/go/src/runtime/mheap.go
type mheap struct {
lock mutex
// spans: 指向mspans区域,用于映射mspan和page的关系
spans []*mspan
// 指向bitmap首地址,bitmap是从高地址向低地址增长的
bitmap uintptr
// 指示arena区首地址
arena_start uintptr
// 指示arena区已使用地址位置
arena_used uintptr
// 指示arena区末地址
arena_end uintptr
central [67*2]struct {
mcentral mcentral
pad [sys.CacheLineSize - unsafe.Sizeof(mcentral{
})%sys.CacheLineSize]byte
}
}
复制代码
mheap:代表Go程序持有的所有堆空间,Go程序使用一个mheap的全局对象_mheap来管理堆内存。
当mcentral没有空闲的mspan时,会向mheap申请。而mheap没有资源时,会向操作系统申请新内存。mheap主要用于大对象的内存分配,以及管理未切割的mspan,用于给mcentral切割成小对象。
同时我们也看到,mheap中含有所有规格的mcentral,所以,当一个mcache从mcentral申请mspan时,只需要在独立的mcentral中使用锁,并不会影响申请其他规格的mspan。
mcentra:l:
为所有mcache提供切分好的mspan资源。每个central保存一种特定大小的全局mspan列表,包括已分配出去的和未分配出去的。 每个mcentral对应一种mspan,而mspan的种类导致它分割的object大小不同。当工作线程的mcache中没有合适(也就是特定大小的)的mspan时就会从mcentral获取。
mcentral被所有的工作线程共同享有,存在多个Goroutine竞争的情况,因此会消耗锁资源

1mheap.central是一个数组,每个元素包含mcentral+padding,长度为136,每一个mcentral对应这一种规格的大小mspan(1-67种规格共68个,scan68+noscan68=136)
spancclass(高7位记录span的大小,最低位记录是否扫描),
partial-可用的span
full-已使用的span,分为已清扫和未清扫

mspan规格:0-32kb
// path: /usr/local/go/src/runtime/sizeclasses.go
const _NumSizeClasses = 67
var class_to_size = [_NumSizeClasses]uint16{
0, 8, 16, 32, 48, 64, 80, 96, 112, 128, 144, 160, 176, 192, 208, 224, 240, 256, 288, 320, 352, 384, 416, 448, 480, 512<

本文深入探讨了Go语言的内存管理机制,包括堆内存的分类与管理,如arena、span和page的组织,以及全局和本地Span管理。详细介绍了mheap、mcentral和mcache的角色,以及它们如何协调进行内存分配和回收。此外,还涵盖了栈的分配、增长、收缩和结束运行的协程栈的处理方式。堆内存分配涉及GC辅助、空间分配、位图标记和收尾工作,而栈管理则涉及到栈空间的动态调整和优化。
最低0.47元/天 解锁文章
7万+

被折叠的 条评论
为什么被折叠?



