1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
|
func growslice(et _type, old slice, cap int) slice {
if raceenabled {
callerpc := getcallerpc()
racereadrangepc(old.array, uintptr(old.lenint(et.size)), callerpc, funcPC(growslice))
}
if msanenabled {
msanread(old.array, uintptr(old.len*int(et.size)))
}
// 如果 cap < old.cap,说明 cap 溢出
if cap < old.cap {
panic(errorString("growslice: cap out of range"))
}
// 如果 et.size, 说明类型大小为 0, 直接返回 zerobase 类型的新切片
if et.size == 0 {
return slice{unsafe.Pointer(&zerobase), old.len, cap}
}
newcap := old.cap
doublecap := newcap + newcap
// 如果需要的容量大于老容量的2倍, 直接将扩容后新容量设置为需要的容量大小
if cap > doublecap {
newcap = cap
} else {
// 如果老容量小于1024, 2倍扩容
if old.len < 1024 {
newcap = doublecap
} else {
// 以1.25倍增大新容量, 直到溢出或者新容量大于需要的容量为止
for 0 < newcap && newcap < cap {
newcap += newcap / 4
}
// 如果溢出,那么将新容量设置为需要的容量
if newcap <= 0 {
newcap = cap
}
}
}
var overflow bool
var lenmem, newlenmem, capmem uintptr
switch {
// 当类型大小为1时,不需要乘除计算就能够得到所需要的值
case et.size == 1:
lenmem = uintptr(old.len)
newlenmem = uintptr(cap)
// 返回mallocgc将分配的内存块的大小。
// 也就是,由Go语言的内存管理模块返回给你需要的内存块,
// 通常这些内存块都是预先申请好,并且被分为常用的规格,比如8,16, 32, 48, 64等。
capmem = roundupsize(uintptr(newcap))
// 判断是否溢出
overflow = uintptr(newcap) > maxAlloc
// 内存对齐,进一步调整newcap
newcap = int(capmem)
// 当类型大小是8个字节时
case et.size == sys.PtrSize:
lenmem = uintptr(old.len) * sys.PtrSize
newlenmem = uintptr(cap) * sys.PtrSize
capmem = roundupsize(uintptr(newcap) * sys.PtrSize)
overflow = uintptr(newcap) > maxAlloc/sys.PtrSize
newcap = int(capmem / sys.PtrSize)
// 当类型大小是2的幂次方时
case isPowerOfTwo(et.size):
var shift uintptr
if sys.PtrSize == 8 {
// Mask shift for better code generation.
shift = uintptr(sys.Ctz64(uint64(et.size))) & 63
} else {
shift = uintptr(sys.Ctz32(uint32(et.size))) & 31
}
lenmem = uintptr(old.len) << shift
newlenmem = uintptr(cap) << shift
capmem = roundupsize(uintptr(newcap) << shift)
overflow = uintptr(newcap) > (maxAlloc >> shift)
newcap = int(capmem >> shift)
// 当大小不是上面任何一种时
default:
lenmem = uintptr(old.len) * et.size
newlenmem = uintptr(cap) * et.size
capmem, overflow = math.MulUintptr(et.size, uintptr(newcap))
capmem = roundupsize(capmem)
newcap = int(capmem / et.size)
}
// 如果发生了溢出
if overflow || capmem > maxAlloc {
panic(errorString("growslice: cap out of range"))
}
var p unsafe.Pointer
// 如果是切片类型是指针类型,那么会调用 memclrNoHeapPointers 将
// newlenmem 以后的 capmem-newlenmem 全部置 0
if et.ptrdata == 0 {
// 申请一块capmem大小的连续内存并返回首地址
p = mallocgc(capmem, nil, false)
memclrNoHeapPointers(add(p, newlenmem), capmem-newlenmem)
} else {
p = mallocgc(capmem, et, true)
if lenmem > 0 && writeBarrier.enabled {
bulkBarrierPreWriteSrcOnly(uintptr(p), uintptr(old.array), lenmem-et.size+et.ptrdata)
}
}
// 将老切片上的元素移动到新的内存中
memmove(p, old.array, lenmem)
// 返回新的切片
return slice{p, old.len, newcap}
}
|