美文网首页
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)
    }

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

相关文章

  • 切片Slice

    切片 slice的内存分析和扩容 超出容量之后扩容会改变切片底层引用的数组的地址,每次扩容成倍扩容 在已有数组上直...

  • Slice 扩容机制解惑

    大家都知道slice扩容机制,在切片长度小于1024时会扩容为原来的2倍,超过1024扩容为原来的1.25倍。其实...

  • go之slice

    slice中文切片的意思,是go独有的类型,底层是数组,可以很方便的进行截取,也支持扩容、拷贝操作 slice 创...

  • slice扩容

    原文:【Golang】slice类型存什么?make和new?slice和数组?扩容规则?_哔哩哔哩_bilibi...

  • 如何获取切片(slice)属性

    获取slice的属性 在登录后,打开slice(切片,为了方便理解,下文所说的切片都是slice)页面。 页面下方...

  • 【golang】slice必知必会

    slice数据结构 slice扩容逻辑 1.如果slice容量足够容纳新增的元素,那么不会扩容。2.如果新增元素后...

  • Go的slice扩容不是全部都按照1.25扩容的,还有内存对齐的

    Go的slice扩容机制-公粽号:堆栈future扩容说实话,我看到别的文章中说slice的扩容很简单,小于102...

  • Go语言学习七:slice

    1. slice 扩容机制 如果 Slice 要扩容的容量大于 2 倍当前的容量,则直接按想要扩容的容量来 new...

  • 《Advanced Swift》笔记4:切片(Slice)

    原文链接:《Advanced Swift》笔记4:切片(Slice) 切片(Slice)是基于任何集合类型(遵守C...

  • Go-Slice

    golang 切片(Slice) 切片为引用类型,切片(Slice)是一个拥有相同类型元素的可变长度的序列。它是基...

网友评论

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

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