-
Notifications
You must be signed in to change notification settings - Fork 0
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
make slice背后的内存管理 #9
Comments
流程make([]byte, 4)
整体流程是:找到一块空间用于存放对象,将该内存空间的地址返回给调用者。 对于go对象的内存管理来说,将对象按照申请的大小分为3类:
所以runtime会根据申请的对象类型不同,进行不同的处理。
|
源码解析具体源码解析如下。 func makeslice(et *_type, len, cap int) unsafe.Pointer {
mem, overflow := math.MulUintptr(et.size, uintptr(cap))
if overflow || mem > maxAlloc || len < 0 || len > cap {
// NOTE: Produce a 'len out of range' error instead of a
// 'cap out of range' error when someone does make([]T, bignumber).
// 'cap out of range' is true too, but since the cap is only being
// supplied implicitly, saying len is clearer.
// See golang.org/issue/4085.
mem, overflow := math.MulUintptr(et.size, uintptr(len))
if overflow || mem > maxAlloc || len < 0 {
panicmakeslicelen()
}
panicmakeslicecap()
}
return mallocgc(mem, et, true)
}
mallocgc 源码位于: // 为一个对象(object)申请内存,单位:bytes
// 小对象(small objects)从各自的P cache上的空闲列表(free lists)中申请;
// 大对象(Large objects,> 32KB)直接从堆(heap)上申请;
func mallocgc(size uintptr, typ *_type, needzero bool) unsafe.Pointer {
// 获取当前的m,并标记状态为正在申请内存(mallocing)
mp := acquirem()
// ...
mp.mallocing = 1
shouldhelpgc := false
dataSize := size
c := gomcache()
var x unsafe.Pointer
noscan := typ == nil || typ.ptrdata == 0
// maxSmallSize:32768(32 * 1024)
if size <= maxSmallSize {
// maxTinySize : 16
// 如果申请的大小小于16字节,并且为不包含指针,则使用tiny allocator申请。
// Tiny allocator的工作原则:
// 1. 使用1个内存块存放所有的tiny对象;
// 2. 不包含指针
// 3. 对象的释放不是显示。如果需要显示地释放对象,申请对象时,确保申请的大小>=16。
//
// tiny allocator的主要作用是为:
// 1. 小字符串
// 2. 逃逸变量
if noscan && size < maxTinySize {
off := c.tinyoffset
// 申请的内存空间做一定的对齐
if size&7 == 0 {
off = alignUp(off, 8)
} else if size&3 == 0 {
off = alignUp(off, 4)
} else if size&1 == 0 {
off = alignUp(off, 2)
}
// 如果申请的对象可以放入当前的tiny内存块,则直接使用该内存块
// 1. 新的对象存放在:地址的起点:c.tiny+off
// 2. tiny的偏移位更新
// 3. mcache的tiny计数器递增
// 4. 释放m的内存申请的状态位
// 5. 释放m与g的关系
if off+size <= maxTinySize && c.tiny != 0 {
// The object fits into existing tiny block.
x = unsafe.Pointer(c.tiny + off)
c.tinyoffset = off + size
c.local_tinyallocs++
mp.mallocing = 0
releasem(mp)
return x
}
// 若上面条件不满足,则申请新的tiny内存块
//
// mcache中的内存管理是由:数组(134)+链表
// 获取一个可用的mspan内存块
span := c.alloc[tinySpanClass]
v := nextFreeFast(span)
if v == 0 {
// 若找不到,则重新申请一份
v, _, shouldhelpgc = c.nextFree(tinySpanClass)
}
// 清空该地址及后面16B的数据
// - tiny objects为16B内存块,所以需要把该地址及后续16B的内存空间清0
// - 清0的方法为:
// 每个uint64为8B,[2]uint64为16B
// 将该地址标示为:2个uint64的数组空间,分别置这2个元素为0
x = unsafe.Pointer(v)
(*[2]uint64)(x)[0] = 0
(*[2]uint64)(x)[1] = 0
// See if we need to replace the existing tiny block with the new one
// based on amount of remaining free space.
if size < c.tinyoffset || c.tiny == 0 {
c.tiny = uintptr(x)
c.tinyoffset = size
}
size = maxTinySize
} else {
// 对于small object的申请,先根据sizeclass找到合适的mspan,然后在对应的sizeclass链表上申请
// 若当前mspan没有,则从mcenter/heap上申请新的
var sizeclass uint8
if size <= smallSizeMax-8 {
sizeclass = size_to_class8[(size+smallSizeDiv-1)/smallSizeDiv]
} else {
sizeclass = size_to_class128[(size-smallSizeMax+largeSizeDiv-1)/largeSizeDiv]
}
size = uintptr(class_to_size[sizeclass])
spc := makeSpanClass(sizeclass, noscan)
span := c.alloc[spc]
v := nextFreeFast(span)
if v == 0 {
v, span, shouldhelpgc = c.nextFree(spc)
}
x = unsafe.Pointer(v)
if needzero && span.needzero != 0 {
memclrNoHeapPointers(unsafe.Pointer(v), size)
}
}
} else {
// 如果是large object(32KB),则直接从heap上申请
var s *mspan
shouldhelpgc = true
systemstack(func() {
s = largeAlloc(size, needzero, noscan)
})
s.freeindex = 1
s.allocCount = 1
x = unsafe.Pointer(s.base())
size = s.elemsize
}
// ...
return x
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
下列程序:申请一个
[]byte
数组,背后的工作机制是如何?The text was updated successfully, but these errors were encountered: