Go 源码之切片 Slice

目录

  • Go 源码之切片 Slice
    • 一、总结
    • 二、源码
      • (一)数据结构
      • (二)创建Slice
      • (三)append-扩容-growslice
      • (四)切片深拷贝

Go 源码之切片 Slice

go源码之Slice - Jxy 博客

一、总结

  • slice是引用类型,底层是一个指向指针的数组,支持动态扩容

  • 底层数据结构(三个字段)

    • array:指向所引用的数组指针(unsafe.Pointer 可以表示任何可寻址的值的指针)

    • len:长度,当前引用切片的元素个数

    • cap:容量,当前引用切片的容量(底层数组的元素总数)

  • 底层扩容机制:当前容量小于1024(256),则 2 倍扩容,反之则为 1.25 倍(2~1.25之间平滑过渡)

  • 扩容创建新的切片,将旧切片数据迁移到新切片,清除旧切片

  • 数组与切片的区别:切片是引用类型,数组是值类型,切片可以动态扩容,底层也是一个数组

二、源码

G O R O O T GOROOT GOROOT\src\runtime\slice.go

(一)数据结构

type slice struct {array unsafe.Pointer 								// 指向所引用的数组指针(`unsafe.Pointer` 可以表示任何可寻址的值的指针)len   int 													// 长度,当前引用切片的元素个数cap   int  													// 容量,cap 一定是大于或等于 len 的。否则会导致 panic
}

(二)创建Slice

makeslice64函数只是做了些校验,其内部也是调用makeslice,

makeslice函数主要是通过len、cap计算slice所需内存大小,然后调用mallocgc进行内存的分配。

// 该函数传入需要初始化的切片的类型,长度以及容量,返回的指针会通过调用方组建成一个完成的slice结构体
func makeslice(et *_type, len, cap int) unsafe.Pointer {// 调用MulUintptr函数:获取创建该切片需要的内存,以及是否溢出mem, overflow := math.MulUintptr(et.size, uintptr(cap))//  如果溢出 | 超过能够分配的最大内存(2^32 - 1) | 非法输入, 报错并返回if overflow || mem > maxAlloc || len < 0 || len > cap {// 下面的注释:// 在创建一个长度非常大的切片时,如果超出了底层数组的容量,通常会发生“cap out of range”错误。// 但是go会优先返回 len 溢出的错误mem, overflow := math.MulUintptr(et.size, uintptr(len))if overflow || mem > maxAlloc || len < 0 {// panic 错误:len溢出panicmakeslicelen()}// panic 错误:容量溢出panicmakeslicecap()}// 调用mallocgc函数分配一块连续内存并返回该内存的首地址return mallocgc(mem, et, true)
}
//MulUintptr返回a*b以及乘法是否溢出。
//在受支持的平台上,这是编译器降低的内在值。
func MulUintptr(a, b uintptr) (uintptr, bool) {if a|b < 1<<(4*goarch.PtrSize) || a == 0 {return a * b, false}overflow := b > MaxUintptr/areturn a * b, overflow
}

(三)append-扩容-growslice

append操作其实是调用了runtime/slice.go中的growslice函数

  • 重新申请内存,之后将数据赋值过来
  • 当原切片cap<1024 时,<新cap> = 2 * <老cap>
  • 当原切片cap>1024 时,<新cap> = 1.25*<老cap>
  • 之后进行内存对齐,内存对齐相关可参考【Golang】详解内存对齐

1.18 最新版本的扩容机制:

  • 小于 256 则 newcap=2 x oldcap
  • 大于 256,则扩容机制 在 2 ~ 1.25 倍 之间,newcap += (newcap + 3*threshold) / 4

(四)切片深拷贝

当我们使用copy时,底层调用的源码函数为makeslicecopy;

这个函数最终就是调用 runtime.memmove 来实现 slice 的 copy 的

func slicecopy(to, fm slice, width uintptr) int {// 如果源切片或者目标切片有一个长度为0,那么就不需要拷贝,直接 return if fm.len == 0 || to.len == 0 {return 0}// n 记录下源切片或者目标切片较短的那一个的长度n := fm.lenif to.len < n {n = to.len}// 如果入参 width = 0,也不需要拷贝了,返回较短的切片的长度if width == 0 {return n}//如果开启竞争检测if raceenabled {callerpc := getcallerpc()pc := funcPC(slicecopy)racewriterangepc(to.array, uintptr(n*int(width)), callerpc, pc)racereadrangepc(fm.array, uintptr(n*int(width)), callerpc, pc)}if msanenabled {msanwrite(to.array, uintptr(n*int(width)))msanread(fm.array, uintptr(n*int(width)))}size := uintptr(n) * widthif size == 1 { // common case worth about 2x to do here// TODO: is this still worth it with new memmove impl?//如果只有一个元素,那么直接进行地址转换*(*byte)(to.array) = *(*byte)(fm.array) // known to be a byte pointer} else {//如果不止一个元素,那么就从 fm.array 地址开始,拷贝到 to.array 地址之后,拷贝个数为sizememmove(to.array, fm.array, size)}return n}

有劳各位看官 点赞、关注➕收藏 ,你们的支持是我最大的动力!!!
接下来会不断更新 golang 的一些底层源码及个人开发经验(个人见解)!!!
同时也欢迎大家在评论区提问、分享您的经验和见解!!!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/786927.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

python pip使用国内镜像

让PIP源使用国内镜像&#xff0c;提升下载速度和安装成功率。 对于Python开发用户来讲&#xff0c;PIP安装软件包是家常便饭。但国外的源下载速度实在太慢&#xff0c;浪费时间。而且经常出现下载后安装出错问题。所以把PIP安装源替换成国内镜像&#xff0c;可以大幅提升下载速…

Division(UVA 725)

网址如下&#xff1a; Division - UVA 725 - Virtual Judge (vjudge.net) &#xff08;第三方网站&#xff09; 考完CSP认证之后动力就有点不足&#xff0c;之后还有一个蓝桥杯&#xff0c;虽然说考的还行&#xff0c;混了个370&#xff0c;但是昨天一天都不怎么想敲代码 昨…

macOS Sonoma 14.4 23E214 VMware系统包下载地址,简单便捷,导入即可用!

这回分享的是VMware虚拟机macOS 14.4版本的系统包&#xff0c;这种系统包是已经在VMware虚拟机中安装好了的macOS系统。省去了繁琐的安装步骤与稍微漫长的等待时间。此次更新的包为诗林工作室制作的最新一个VMware系统包版本。分享给那些想快速体验macOS 14版本的朋友。 使用方…

C++ AVL树(旋转)

我们之前学习了搜索二叉树&#xff0c;我们知道普通的搜索二叉树会有特殊情况出现使得二叉树的两枝极其不平衡形成我们通俗说的歪脖子树&#xff1a; 这样的树一定会使得我们的增删查的效率变低&#xff1b;为了避免这种极端的情况出现&#xff0c;在1962年有两位伟大的俄罗斯数…

Unix消息队列实例

我们创建三个文件&#xff0c;一个recieve.c和pa.c,pb.c 。用recieve.c来监听pa.c和pb.c发送的消息&#xff1a; recieve.c代码&#xff1a; #include<t_stdio.h>#include <sys/types.h> #include <sys/ipc.h> #include <sys/msg.h> #include <str…

数据库理论

什么是表空间 表空间是数据库的逻辑划分&#xff0c;一个表空间只能属于一个数据库。所有的数据库对象都存放在指定的表空间中。但主要存放的是表&#xff0c; 所以称作表空间。Oracle数据库中至少存在一个表空间&#xff0c;即SYSTEM的表空间。表空间不足怎么办 先查看Oracle数…

计算机断层扫描采集软件

计算机断层扫描采集软件&#xff0c;通过x采集2D和3D投影&#xff0c;利用投影可以进行体积的重建&#xff0c;软件还集成了CNC和x射线球管控制功能&#xff0c; 用PDM进程数据管理器对数据和进程进行管理&#xff0c;并对外提供与数据通信的接口 PDM通信基于AMQP&#xff0c…

Apple Vision Pro 的组成结构

Apple Vision Pro的组成结构相当复杂且精密,下面我将为您详细介绍其主要组成部分: 3D层压抛光玻璃面板与铝合金框架:Vision Pro的正面设计独特,类似于一副滑雪镜。它采用一块弧形的3D层压抛光玻璃面板,与定制的铝合金框架紧密结合。这个框架在用户的脸周围轻轻弯曲,以更好…

EasyExcel 复杂表头的导出(动态表头和静态表头)

问题&#xff1a;如图&#xff0c;1部分的表头是动态的根据日期变化&#xff0c;2部分是数据库对应的字段&#xff0c;静态不变的&#xff1b; 解决方案&#xff1a;如果不看1的部分&#xff0c;2部分内容可以根据实体类注解的方式导出&#xff0c;那么我们是不是可以先将动态表…

Centos7 安装 Oracle19c

下载oracle预安装包 wget http://yum.oracle.com/repo/OracleLinux/OL7/latest/x86_64/getPackage/oracle-database-preinstall-19c-1.0-1.el7.x86_64.rpm 下载19c安装包 https://www.oracle.com/cn/database/technologies/oracle-database-software-downloads.html#19c 选择…

Oracle 数据库工作中常用知识点:sql语法与常用函数

.to_date()函数 to_date函数是Oracle特有的函数&#xff0c;该函数用来做日期转换。 举例&#xff1a; SELECT TO_DATE(‘2006-05-01 19:25:34’, ‘YYYY-MM-DD HH24:MI:SS’) FROM DUAL   日期格式&#xff1a;     YYYY、YYY、YY 分别代表4位、3位、2位的数字年    …

RESTfull接口访问Elasticsearch

【数据库的健康值】 curl -X GET "ip:9200/_cat/health" 【查看所有索引】 curl -X GET "ip:9200/_cat/indices?v" 【查看索引index_name】 curl -X GET "ip:9200/索引?pretty" 【创建索引/文档】 PUT "ip:9200/索引/文档id" {请…

Java中的原型模式

Java中的原型模式是一种创建型设计模式&#xff0c;它通过复制已有对象来创建新的对象&#xff0c;而不是每次都创建一个新的实例。这个模式适用于那些创建新对象的成本较大或者需要保持对象属性一致性的场景。在Java中&#xff0c;通常通过实现Cloneable接口并重写Object类中的…

计算机网络-HTTP相关知识-HTTPS基础

HTTP与HTTPS的区别&#xff1a; HTTPS在TCP和HTTP网络层之间加入了SSL/TLS安全协议层。这个安全协议层可以对数据进行加密&#xff0c;确保数据在传输过程中的安全。HTTPS在TCP三次握手之后&#xff0c;还需进行SSL/TLS的握手过程。这个握手过程主要是为了在客户端和服务器之间…

超声波清洗机是干什么用的?2024年有用的超声波清洗机推荐

随着科技的不断进步&#xff0c;超声波清洗机已经成为了家庭和专业场所不可或缺的高效清洁工具。它利用超声波波动产生的微小气泡来清洁物品表面及细缝中的污渍&#xff0c;实现深层次的清洁效果。特别是对于眼镜这样的精密物品&#xff0c;定期进行深度清洁不仅能够确保视觉的…

【算法刷题day10】Leetcode:232.用栈实现队列、225. 用队列实现栈

文章目录 Leetcode 232.用栈实现队列解题思路代码总结 Leetcode 225. 用队列实现栈解题思路代码总结 stack、queue和deque对比 草稿图网站 java的Deque Leetcode 232.用栈实现队列 题目&#xff1a;232.用栈实现队列 解析&#xff1a;代码随想录解析 解题思路 一个栈负责进&a…

【C++】每日一题 12 整数转罗马数字

罗马数字包含以下七种字符&#xff1a; I&#xff0c; V&#xff0c; X&#xff0c; L&#xff0c;C&#xff0c;D 和 M。 字符 数值 I 1 V 5 X 10 L 50 C 100 D 500 M 1000 例如&#xff0c; 罗马数字 2 写做 II &#xff0c;即为两个并列的 1。12 写做 XII &#xff0c;即为…

前端二维码生成工具小程序:构建营销神器的技术解析

摘要&#xff1a; 随着数字化营销的不断深入&#xff0c;二维码作为一种快速、便捷的信息传递方式&#xff0c;已经广泛应用于各个领域。本文旨在探讨如何通过前端技术构建一个功能丰富、操作简便的二维码生成工具小程序&#xff0c;为企业和个人提供高效的营销支持。 一、引言…

如何使用 Grep 命令在 Linux 中搜索文件

如何使用 Grep 命令在 Linux 中搜索文件 Grep 命令代表 “全局正则表达式输出” 是 Linux 中最强大和最常用的命令之一。 Grep 在一个或多个输入文件中搜索与给定模式匹配的行&#xff0c;并将每个匹配行写入标准输出。 如果没有指定文件&#xff0c;则 grep 从标准输入读取&…

什么是过载

宇航员相关知识会涉及到过载&#xff0c;导弹相关知识也会涉及到过载&#xff0c;如导弹的过载加速度&#xff0c;什么是过载呢&#xff1f;博主从B站上看到一UP主讲的很好&#xff0c; 该up主视频链接&#xff1a; 过载是什么_哔哩哔哩_bilibili 内容截图如下&#xff1a;