slice是如何扩容的
发表于:2025-01-31 作者:千家信息网编辑
千家信息网最后更新 2025年01月31日,本篇内容介绍了"slice是如何扩容的"的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!问题1,slic
千家信息网最后更新 2025年01月31日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安全错误
数据库的锁怎样保障安全
专业性网络技术咨询销售方法
emobile7登陆服务器是
兰帕网络技术深圳有限公司
网络安全边界包括什么
组织开展网络安全知识测试
为什么会有多个数据库
udp 开源高并发服务器
景德镇主机服务器哪里比较好
用数据库创建一张教材表
毕马威网络安全保险预测
软件开发公司人力资源文案
无锡crm软件开发工程师
电脑信息包括网络技术吗
口袋妖怪数据库下载
hpe服务器管理口地址
湖南冰壶网络技术有限公司
触犯刑法的人从事网络安全
网络技术与布线
学网络安全为什么要学c语言
西工大网络安全试题及答案
脸书是什么软件开发的
米波现场200人服务器要求
解决网络安全的创新性举措
南京服务器机柜定制报价
大学生网络安全宣传月主题
还原sql数据库
买水果网络安全段子
打印机服务器 固网
湖北java软件开发培训
南京三堂软件开发