扫码订阅《 》或入驻星球,即可阅读文章!

GOLANG ROADMAP

阅读模式

  • 沉浸
  • 自动
  • 日常
首页
Go学习
  • Go学院

    • Go小课
    • Go小考
    • Go实战
    • 精品课
  • Go宝典

    • 在线宝典
    • B站精选
    • 推荐图书
    • 精品博文
  • Go开源

    • Go仓库
    • Go月刊
  • Go下载

    • 视频资源
    • 文档资源
Go求职
  • 求职服务

    • 内推互助
    • 求职助力
  • 求职刷题

    • 企业题库
    • 面试宝典
    • 求职面经
Go友会
  • 城市
  • 校园
推广返利 🤑
实验区
  • Go周边
消息
更多
  • 用户中心

    • 我的信息
    • 推广返利
  • 玩转星球

    • 星球介绍
    • 角色体系
    • 星主权益
  • 支持与服务

    • 联系星主
    • 成长记录
    • 常见问题
    • 吐槽专区
  • 合作交流

    • 渠道合作
    • 课程入驻
    • 友情链接
author-avatar

GOLANG ROADMAP


首页
Go学习
  • Go学院

    • Go小课
    • Go小考
    • Go实战
    • 精品课
  • Go宝典

    • 在线宝典
    • B站精选
    • 推荐图书
    • 精品博文
  • Go开源

    • Go仓库
    • Go月刊
  • Go下载

    • 视频资源
    • 文档资源
Go求职
  • 求职服务

    • 内推互助
    • 求职助力
  • 求职刷题

    • 企业题库
    • 面试宝典
    • 求职面经
Go友会
  • 城市
  • 校园
推广返利 🤑
实验区
  • Go周边
消息
更多
  • 用户中心

    • 我的信息
    • 推广返利
  • 玩转星球

    • 星球介绍
    • 角色体系
    • 星主权益
  • 支持与服务

    • 联系星主
    • 成长记录
    • 常见问题
    • 吐槽专区
  • 合作交流

    • 渠道合作
    • 课程入驻
    • 友情链接
  • 面试宝典系列

    • Golang面试题汇总
  • 宝典内容

    • 1.Golang中除了加Mutex锁以外还有哪些方式安全读写共享变量
    • 2.无缓冲Chan的发送和接收是否同步?
    • 3.Golang并发机制以及它所使用的CSP并发模型
    • 4.Golang中常用的并发模型
    • 5.Go中对nil的Slice和空Slice的处理是一致的吗?
    • 6.协程和线程和进程的区别?
    • 7.Golang的内存模型中为什么小对象多了会造成GC压力?
    • 8.Go中数据竞争问题怎么解决?
    • 9.什么是channel,为什么它可以做到线程安全?
    • 10.Golang垃圾回收算法?
    • 11.GC的触发条件
    • 12.Go的GPM如何调度?
    • 13.并发编程概念是什么?
    • 14.Go语言的栈空间管理是怎么样的?
    • 15.Goroutine和Channel的作用分别是什么?
    • 16.怎么查看Goroutine的数量?
    • 17.Go中的锁有哪些?
    • 18.怎么限制Goroutine的数量?
    • 19.Channel是同步的还是异步的?
    • 20.Goroutine和线程的区别?
    • 21.Go的Struct能不能比较?
    • 22.Go的defer原理是什么?
    • 23.Go的select可以用于什么?
    • 24.Context包的用途是什么?
    • 25.Go主协程如何等其余协程完再操作?
    • 26.Go的Slice如何扩容?
    • 27.Go中的map如何实现顺序读取?
    • 28.Go中CAS是怎么回事?
    • 29.Go中的逃逸分析是什么?
    • 30.Go值接收者和指针接收者的区别?
    • 31.Go的对象在内存中是怎样分配的?
    • 32.栈的内存是怎么分配的?
    • 33.堆内存管理怎么分配的?
    • 34.Go中的defer函数使用下面的两种情况下结果是什么?
    • 35.在Go函数中为什么会发生内存泄露?
    • 36.Go中new和make的区别?
    • 37.G0的作用?
    • 38.Go中的锁如何实现?
    • 39.Go中的channel的实现?
    • 40.Go中的map的实现
    • 41.Go中的http包的实现原理?
    • 42.Goroutine发生了泄漏如何检测?
    • 43.Go函数返回局部变量的指针是否安全?
    • 44.Go中两个Nil可能不相等吗?
    • 45.Goroutine和KernelThread之间是什么关系?

扫码订阅《 》或入驻星球,即可阅读文章!

26.Go的Slice如何扩容?


面试宝典
Go的Slice如何扩容

slice是 Go 中的一种基本的数据结构,使用这种结构可以用来管理数据集合。但是slice本身并不是动态数据或者数组指针。slice常见的操作有 reslice、append、copy。

slice自身并不是动态数组或者数组指针。它内部实现的数据结构通过指针引用底层数组,设定相关属性将数据读写操作限定在指定的区域内。slice本身是一个只读对象,其工作机制类似数组指针的一种封装。

slice是对数组一个连续片段的引用,所以切片是一个引用类型(因此更类似于 C/C++ 中的数组类型,或者 Python 中的 list类型)。这个片段可以是整个数组,或者是由起始和终止索引标识的一些项的子集。

这里需要注意的是,终止索引标识的项不包括在切片内。切片提供了一个与指向数组的动态窗口。

slice是可以看做是一个长度可变的数组。

slice数据结构如下:

type slice struct {
	array unsafe.Pointer
	len   int
	cap   int
}
1
2
3
4
5

slice的结构体由3部分构成,Pointer 是指向一个数组的指针,len 代表当前切片的长度,cap 是当前切片的容量。cap 总是大于等于 len 的。

通常我们在对slice进行append等操作时,可能会造成slice的自动扩容。

其扩容时的大小增长规则是:

  • 如果切片的容量小于1024个元素,那么扩容的时候slice的cap就翻番,乘以2;一旦元素个数超过1024个元素,增长因子就变成1.25,即每次增加原来容量的四分之一。

  • 如果扩容之后,还没有触及原数组的容量,那么,切片中的指针指向的位置,就还是原数组,如果扩容之后,超过了原数组的容量,那么,Go就会开辟一块新的内存,把原来的值拷贝过来,这种情况丝毫不会影响到原数组。

通过slice源码可以看到,append的实现只是简单的在内存中将旧slice复制给新slice.

newcap := old.cap

if newcap+newcap < cap {
    newcap = cap
} else {
    for {
        if old.len < 1024 {
            newcap += newcap
        } else {
            newcap += newcap / 4
        }
        if newcap >= cap {
            break
        }
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16