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中的源码

go 复制代码
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作者给出了几种原始容量下对应的"扩容系数":

相关推荐
追逐时光者6 小时前
精选 4 款基于 .NET 开源、功能强大的 Windows 系统优化工具
后端·.net
TF男孩6 小时前
ARQ:一款低成本的消息队列,实现每秒万级吞吐
后端·python·消息队列
AAA修煤气灶刘哥7 小时前
别让Redis「歪脖子」!一次搞定数据倾斜与请求倾斜的捉妖记
redis·分布式·后端
AAA修煤气灶刘哥7 小时前
后端人速藏!数据库PD建模避坑指南
数据库·后端·mysql
你的人类朋友8 小时前
什么是API签名?
前端·后端·安全
昵称为空C10 小时前
SpringBoot3 http接口调用新方式RestClient + @HttpExchange像使用Feign一样调用
spring boot·后端
架构师沉默10 小时前
设计多租户 SaaS 系统,如何做到数据隔离 & 资源配额?
java·后端·架构
RoyLin11 小时前
TypeScript设计模式:适配器模式
前端·后端·node.js
该用户已不存在11 小时前
Mojo vs Python vs Rust: 2025年搞AI,该学哪个?
后端·python·rust
Moonbit11 小时前
MoonBit 正式加入 WebAssembly Component Model 官方文档 !
前端·后端·编程语言