slice是如何扩容的
发表于:2025-11-11 作者:千家信息网编辑
千家信息网最后更新 2025年11月11日,本篇内容介绍了"slice是如何扩容的"的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!问题1,slic
千家信息网最后更新 2025年11月11日slice是如何扩容的问题1,slice的底层数据结构
本篇内容介绍了"slice是如何扩容的"的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!
问题1,slice的底层数据结构
我擦,这么直接的嘛?
我猜是数组加链表,结果猜错了0分。
翻看源码。
runtime/slice.go
type slice struct { array unsafe.Pointer //数据结构是简单粗暴的数组指针 len int cap int}问题2,slice是如何扩容的
又猜错了~
还是继续看源码吧
从源码找了半天,发现一个这。
growslice handles slice growth during append.
so,就是你了。
func growslice(et *_type, old slice, cap int) slice { // 第三个cap,新的最小容量 //巴拉巴拉巴拉 一堆判断 newcap := old.cap //变量存储空间大小 doublecap := newcap + newcap //双倍空间大小 if cap > doublecap { //如果历史空间大于双倍的容量,新的最小容量 newcap = cap } else { //如果长度小于 1024 新长度就是2倍老容量 if old.len < 1024 { newcap = doublecap } else { //当大于1024 走公式 newcap += newcap / 4,直到newcap大于等于老cap for 0 < newcap && newcap < cap { newcap += newcap / 4 } if newcap <= 0 { newcap = cap } } } var overflow bool var lenmem, newlenmem, capmem uintptr //对et的size做匹配,获取需要申请的空间大小 //1 不处理直接分配 //系统指针大小 进行计算和位运算 //2 唯一运算 //默认 相乘 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 == sys.PtrSize: lenmem = uintptr(old.len) * sys.PtrSize newlenmem = uintptr(cap) * sys.PtrSize capmem = roundupsize(uintptr(newcap) * sys.PtrSize) overflow = uintptr(newcap) > maxAlloc/sys.PtrSize newcap = int(capmem / sys.PtrSize) case isPowerOfTwo(et.size): var shift uintptr if sys.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) } //如果append一次超过过多的元素新增,直接报错,越界,超出容量大小 if overflow || capmem > maxAlloc { panic(errorString("growslice: cap out of range")) } var p unsafe.Pointer //申请新的内存,并把指针指向p if et.ptrdata == 0 { p = mallocgc(capmem, nil, false) memclrNoHeapPointers(add(p, newlenmem), capmem-newlenmem) } else { p = mallocgc(capmem, et, true) if lenmem > 0 && writeBarrier.enabled { bulkBarrierPreWriteSrcOnly(uintptr(p), uintptr(old.array), lenmem) } } //将老的数据移动到新的数据 memmove(p, old.array, lenmem) return slice{p, old.len, newcap}}总结
其实可以看出,golang的切片扩容是比较粗暴的,直接赋值拷贝。不过,golang区分的长度和容量两种单位计量,一般会提前分配足够的cap,可以减少maclloc的次数。
"slice是如何扩容的"的内容就介绍到这里了,感谢大家的阅读。如果想了解更多行业相关的知识可以关注网站,小编将为大家输出更多高质量的实用文章!
容量
数据
大小
源码
空间
长度
最小
粗暴
内容
双倍
就是
指针
数据结构
数组
更多
知识
结构
问题
巴拉
实用
数据库的安全要保护哪些东西
数据库安全各自的含义是什么
生产安全数据库录入
数据库的安全性及管理
数据库安全策略包含哪些
海淀数据库安全审计系统
建立农村房屋安全信息数据库
易用的数据库客户端支持安全管理
连接数据库失败ssl安全错误
数据库的锁怎样保障安全
杭电数据库张红娟第5章答案
对网络安全有什么影响
剑阁网络安全宣传
安全生产意识形态网络安全
nginx服务器做游戏
家用电脑dns服务器地址是多少
sql数据库难不难
实际工作中如何做到网络安全
网络安全法确立了谁原则
深圳web前端软件开发定制
邮储银行网络安全事故
win7应用程序服务器
服务器空间大小
河北PLC编程软件开发公司
cisco服务器图标
服务器托管一般多少钱
三级网络技术很容易吗
12123申请免检标志服务器异常
怎样装服务器系统
软件开发课题论文怎么写
数据库的面试问题吗
99gan无法连接服务器
方兴互联网科技信息
服务器上缺少jar包
服务器人员需要做什么
网络安全饭团乱象
苏州公司网络安全准入控制系统
医疗设备网络安全风险评估
网络安全与诈骗的知识
考勤管理系统数据库连接