增长切片时扩展内存(逻辑增长底层数组的容量)
Extend memory when grow slice (logic grow capacity underlying array)
我知道(并在互联网上阅读 - 包括此资源)。增加内存的逻辑是:if len array less than 1024 - golang multiply array on 2 else multiply len on 1.25(我们在源代码中看到这个毫无疑问https://github.com/golang/go/blob/cb2353deb74ecc1ca2105be44881c5d563a00fb8/src/runtime/slice.go#L95)
但是如果我在循环中填充切片,我会看到这种行为
t := []int{}
z := 0
for i := 1; i < 10000; i++ {
t = append(t, i)
if z < cap(t) {
z = cap(t)
fmt.Println(" len - ", len(t), " : cap - ", cap(t))
}
}
len a.k.a。数
len - 1 : cap - 1
len - 2 : cap - 2
len - 3 : cap - 4
len - 5 : cap - 8
len - 9 : cap - 16
len - 17 : cap - 32
len - 33 : cap - 64
len - 65 : cap - 128
len - 129 : cap - 256
len - 257 : cap - 512
len - 513 : cap - 1024
len - 1025 : cap - 1280
len - 1281 : cap - 1696
len - 1697 : cap - 2304
len - 2305 : cap - 3072
len - 3073 : cap - 4096
len - 4097 : cap - 5120
len - 5121 : cap - 7168
len - 7169 : cap - 9216
len - 9217 : cap - 12288
before len 513 - capacity grow x2
len 1025 = 1.25 * len 513 = 1280 - capacity grow x1.25 (ok)
next capacity 1280*1.25 = 1600, but i see 1696 (len 1281).
Why difference = 96?
len 1281 - 3073 wrong, but len 3073 * 1.25 = 5120 (len 4097)
如果golang在增加slice时可以增加数组容量,那么当引用它的slice太小时它是否可以减少数组?
谢谢!
next capacity 1280*1.25 = 1600, but i see 1696 (len 1281).
src/runtime/malloc.go
// Small allocation sizes (up to and including 32 kB) are
// rounded to one of about 70 size classes, each of which
// has its own free set of objects of exactly that size.
growslice
请求最小分配大小。 mallocgc
执行分配。 mallocgc
四舍五入到 class 大小以最小化碎片。
写一个收缩内存函数。
package main
import "fmt"
func shrink(s []byte) []byte {
if (cap(s)-len(s))/len(s) >= 1 {
t := s
s = make([]byte, len(s), 2*len(s))
copy(s, t)
}
return s
}
func main() {
s := make([]byte, 32, 256)
fmt.Println(len(s), cap(s))
s = shrink(s)
fmt.Println(len(s), cap(s))
}
游乐场:https://play.golang.org/p/udAEBJ-kWQ9
输出:
32 256
32 64
如您所见,它会耗费时间和内存。只有您可以决定在您的特定情况下是否值得。
我知道(并在互联网上阅读 - 包括此资源)。增加内存的逻辑是:if len array less than 1024 - golang multiply array on 2 else multiply len on 1.25(我们在源代码中看到这个毫无疑问https://github.com/golang/go/blob/cb2353deb74ecc1ca2105be44881c5d563a00fb8/src/runtime/slice.go#L95) 但是如果我在循环中填充切片,我会看到这种行为
t := []int{}
z := 0
for i := 1; i < 10000; i++ {
t = append(t, i)
if z < cap(t) {
z = cap(t)
fmt.Println(" len - ", len(t), " : cap - ", cap(t))
}
}
len a.k.a。数
len - 1 : cap - 1
len - 2 : cap - 2
len - 3 : cap - 4
len - 5 : cap - 8
len - 9 : cap - 16
len - 17 : cap - 32
len - 33 : cap - 64
len - 65 : cap - 128
len - 129 : cap - 256
len - 257 : cap - 512
len - 513 : cap - 1024
len - 1025 : cap - 1280
len - 1281 : cap - 1696
len - 1697 : cap - 2304
len - 2305 : cap - 3072
len - 3073 : cap - 4096
len - 4097 : cap - 5120
len - 5121 : cap - 7168
len - 7169 : cap - 9216
len - 9217 : cap - 12288
before len 513 - capacity grow x2
len 1025 = 1.25 * len 513 = 1280 - capacity grow x1.25 (ok)
next capacity 1280*1.25 = 1600, but i see 1696 (len 1281).
Why difference = 96?
len 1281 - 3073 wrong, but len 3073 * 1.25 = 5120 (len 4097)
如果golang在增加slice时可以增加数组容量,那么当引用它的slice太小时它是否可以减少数组?
谢谢!
next capacity 1280*1.25 = 1600, but i see 1696 (len 1281).
src/runtime/malloc.go
// Small allocation sizes (up to and including 32 kB) are // rounded to one of about 70 size classes, each of which // has its own free set of objects of exactly that size.
growslice
请求最小分配大小。 mallocgc
执行分配。 mallocgc
四舍五入到 class 大小以最小化碎片。
写一个收缩内存函数。
package main
import "fmt"
func shrink(s []byte) []byte {
if (cap(s)-len(s))/len(s) >= 1 {
t := s
s = make([]byte, len(s), 2*len(s))
copy(s, t)
}
return s
}
func main() {
s := make([]byte, 32, 256)
fmt.Println(len(s), cap(s))
s = shrink(s)
fmt.Println(len(s), cap(s))
}
游乐场:https://play.golang.org/p/udAEBJ-kWQ9
输出:
32 256
32 64
如您所见,它会耗费时间和内存。只有您可以决定在您的特定情况下是否值得。