go中Slice扩容机制新更新

简介: go中Slice扩容机制新更新

前言

对于golang初学者来讲,golang的扩容机制是比较懵逼的,而在go1.18中golang的扩容机制迎来了更新


一、旧版本


```go
newcap := old.cap
doublecap := newcap + newcap
if cap > doublecap {
   
   
    newcap = cap
} else {
   
   
    if old.len < 1024 {
   
   
        newcap = doublecap
    } else {
   
   
        // Check 0 < newcap to detect overflow
        // and prevent an infinite loop.
        for 0 < newcap && newcap < cap {
   
   
            newcap += newcap / 4
        }
        // Set newcap to the requested cap when
        // the newcap calculation overflowed.
        if newcap <= 0 {
   
   
            newcap = cap
        }
    }
}

这是$GOROOT/src/runtime/slice.go里的源码,说的比较清楚,

首先判断,如果新申请容量(cap)大于2倍的旧容量(old.cap),最终容量(newcap)就是新申请的容量(cap)。
否则判断,如果旧切片的长度小于1024,则最终容量(newcap)就是旧容量(old.cap)的两倍,即(newcap=doublecap),
否则判断,如果旧切片长度大于等于1024,则最终容量(newcap)从旧容量(old.cap)开始循环增加原来的1/4,即(newcap=old.cap,for
{newcap += newcap/4})直到最终容量(newcap)大于等于新申请的容量(cap),即(newcap >= cap)
如果最终容量(cap)计算值溢出,则最终容量(cap)就是新申请容量(cap)。

二、go1.18的更新

这是go1.18中的源码

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
            }
        }
    }

对比新版扩容与旧版可以看出差别就是:
旧版是和1024比较,
而新版是和256比较,
并且系数也从1.25变成了 newcap += (newcap + 3*threshold) / 4

总结

在1.18中,优化了切片扩容的策略2,让底层数组大小的增长更加平滑:
通过减小阈值并固定增加一个常数,使得优化后的扩容的系数在阈值前后不再会出现从2到1.25的突变,该commit作者给出了几种原始容量下对应的“扩容系数”:

在这里插入图片描述

相关文章
|
1月前
|
存储 安全 Go
Go 语言以其高效的并发编程能力著称,主要依赖于 goroutines 和 channels 两大核心机制
Go 语言以其高效的并发编程能力著称,主要依赖于 goroutines 和 channels 两大核心机制。本文介绍了这两者的概念、用法及如何结合使用,实现任务的高效并发执行与数据的安全传递,强调了并发编程中的注意事项,旨在帮助开发者更好地掌握 Go 语言的并发编程技巧。
35 2
|
1月前
|
存储 算法 Java
Go语言的内存管理机制
【10月更文挑战第25天】Go语言的内存管理机制
35 2
|
4月前
|
存储 编译器 Go
|
4月前
|
人工智能 Go
go slice 扩容实现
go slice 扩容实现
55 3
|
4月前
|
人工智能 编译器 Go
go slice 基本用法
go slice 基本用法
59 1
|
4月前
|
Go 数据处理
|
4月前
|
存储 算法 Go
|
4月前
|
监控 Serverless Go
Golang 开发函数计算问题之Go 语言中切片扩容时需要拷贝原数组中的数据如何解决
Golang 开发函数计算问题之Go 语言中切片扩容时需要拷贝原数组中的数据如何解决
|
6月前
|
Java Go
Go 中 slice 的内存管理机制
Go 中 slice 的内存管理机制