为什么奇数的切片容量与偶数的行为不同

我注意到当容量为奇数时,切片的容量以不同的方式表现。更具体地说:当一个元素添加到切片时,当原始容量为偶数时,切片的容量增加一倍。但是当原始容量为奇数时,容量增加一然后翻倍。例子:


s := make([]int, 28, 28)

s = append(s, 1) 

fmt.Println("len=", len(s), " cap=", cap(s)) // len = len + 1, cap = 2 * cap



pri := make([]int, 27, 27)

pri = append(pri, 1)

fmt.Println("len=", len(pri), " cap=", cap(pri)) // len = len + 1, cap = 2 * (cap + 1)  

假设这不是错误,这种行为的原因是什么?


游乐场链接:http : //play.golang.org/p/wfmdobgCUF


暮色呼如
浏览 199回答 1
1回答

慕虎7371278

简答它正在舍入切片容量以填充分配的内存块。长答案让我们来看看 Go1.5.1 源代码:https://github.com/golang/go/blob/f2e4c8b5fb3660d793b2c545ef207153db0a34b1/src/cmd/compile/internal/gc/walk.go#L2895告诉我们append(l1, l2...)扩展为s := l1if n := len(l1) + len(l2) - cap(s); n > 0 {&nbsp; &nbsp; s = growslice_n(s, n)}s = s[:len(l1)+len(l2)]memmove(&s[len(l1)], &l2[0], len(l2)*sizeof(T))我们感兴趣的部分growslice_n,在那里定义:https : //github.com/golang/go/blob/f2e4c8b5fb3660d793b2c545ef207153db0a34b1/src/runtime/slice.go#L36再深入一点,我们发现:newcap := old.capif newcap+newcap < cap {&nbsp; &nbsp; newcap = cap} else {&nbsp; &nbsp; for {&nbsp; &nbsp; &nbsp; &nbsp; if old.len < 1024 {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; newcap += newcap&nbsp; &nbsp; &nbsp; &nbsp; } else {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; newcap += newcap / 4&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; if newcap >= cap {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; break&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; }}/* [...] */capmem := roundupsize(uintptr(newcap) * uintptr(et.size))newcap = int(capmem / uintptr(et.size))roundupsize在那里定义:https : //github.com/golang/go/blob/f2e4c8b5fb3660d793b2c545ef207153db0a34b1/src/runtime/msize.go#L178// Returns size of the memory block that mallocgc will allocate if you ask for the size.func roundupsize(size uintptr) uintptr {&nbsp; &nbsp; if size < _MaxSmallSize {&nbsp; &nbsp; &nbsp; &nbsp; if size <= 1024-8 {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return uintptr(class_to_size[size_to_class8[(size+7)>>3]])&nbsp; &nbsp; &nbsp; &nbsp; } else {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return uintptr(class_to_size[size_to_class128[(size-1024+127)>>7]])&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; }&nbsp; &nbsp; if size+_PageSize < size {&nbsp; &nbsp; &nbsp; &nbsp; return size&nbsp; &nbsp; }&nbsp; &nbsp; return round(size, _PageSize)}它是在那里介绍的:https : //groups.google.com/forum/#!topic/golang-codereviews/bFGtI4Cpb_M增长切片时要考虑分配的内存块的大小。
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Go