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

相关推荐
2401_824256863 分钟前
Scala的函数式编程
开发语言·后端·scala
小杨4041 小时前
springboot框架项目实践应用十四(扩展sentinel错误提示)
spring boot·后端·spring cloud
陈大爷(有低保)1 小时前
Spring中都用到了哪些设计模式
java·后端·spring
程序员 小柴1 小时前
SpringCloud概述
后端·spring·spring cloud
喝醉的小喵1 小时前
分布式环境下的主从数据同步
分布式·后端·mysql·etcd·共识算法·主从复制
雷渊2 小时前
深入分析mybatis中#{}和${}的区别
java·后端·面试
我是福福大王2 小时前
前后端SM2加密交互问题解析与解决方案
前端·后端
老友@2 小时前
Kafka 全面解析
服务器·分布式·后端·kafka
Java中文社群2 小时前
超实用!Prompt程序员使用指南,大模型各角色代码实战案例分享
后端·aigc
风象南3 小时前
Spring Boot 实现文件秒传功能
java·spring boot·后端