美文网首页
golang1.19 slice(切片) 扩容规则

golang1.19 slice(切片) 扩容规则

作者: 十年磨一剑1111 | 来源:发表于2023-08-08 17:56 被阅读0次

    写上一段源码,在src/runtime/slice.go growslice函数(以下是截取部分源码):

    newcap := old.cap
        doublecap := newcap + newcap
        if cap > doublecap {
            newcap = cap
        } else {
            const threshold = 256
            if old.cap < threshold {
                newcap = doublecap
            } else {
                // Check 0 < newcap to detect overflow
                // and prevent an infinite loop.
                for 0 < newcap && newcap < cap {
                    // Transition from growing 2x for small slices
                    // to growing 1.25x for large slices. This formula
                    // gives a smooth-ish transition between the two.
                    newcap += (newcap + 3*threshold) / 4
                }
                // Set newcap to the requested cap when
                // the newcap calculation overflowed.
                if newcap <= 0 {
                    newcap = cap
                }
            }
        }
    

    golang 切片扩容规则:

    1. 当预期的容量(cap)要大于原容量的2倍时,新的容量就是预期的容量;
    2. 当预期的容量小于等于原容量的2倍时,如果原容量小于256,新的容量就是原来的两倍,
      当原容量大于等于256时,每次会扩容原来容量的1.25倍加上192,直到新的容量大于等于预期容量;
    3. 实际申请的内存不是严格按照上面的规则,会有一个roundupsize操作,通俗来讲也就是golang内存优化;
      内存优化源码如下(以下是部分源码):
    switch {
        case et.size == 1:
            lenmem = uintptr(old.len)
            newlenmem = uintptr(cap)
            capmem = roundupsize(uintptr(newcap))
            overflow = uintptr(newcap) > maxAlloc
            newcap = int(capmem)
        case et.size == goarch.PtrSize:
            lenmem = uintptr(old.len) * goarch.PtrSize
            newlenmem = uintptr(cap) * goarch.PtrSize
            capmem = roundupsize(uintptr(newcap) * goarch.PtrSize)
            overflow = uintptr(newcap) > maxAlloc/goarch.PtrSize
            newcap = int(capmem / goarch.PtrSize)
        case isPowerOfTwo(et.size):
            var shift uintptr
            if goarch.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)
        }
    

    至于内存优化具体操作笔者在这里就不详细说了,感兴趣的朋友可以私聊我哦。

    相关文章

      网友评论

          本文标题:golang1.19 slice(切片) 扩容规则

          本文链接:https://www.haomeiwen.com/subject/bdznpdtx.html