扩容的源码
func growslice(et *_type, old slice, cap int) slice {
...
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
}
}
}
...
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)
}
}

package main

import (
"fmt"
"unsafe"
) type ss struct {
ptr unsafe.Pointer
l int
c int
} type A struct {
f bool
b int32
a int
c int64
d string
} func main() {
Af()
return
} func Af() {
a := make([]A, , )
b := A{} fmt.Println("Sizeof A:", unsafe.Sizeof(b)) p1 := (*ss)(unsafe.Pointer(&a))
fmt.Printf("len=%d,cap=%d,ptr=%p\n", len(a), cap(a), p1)
a = append(a, A{}, A{}, A{}, A{})
fmt.Printf("len=%d,cap=%d,ptr=%p\n", len(a), cap(a), p1) for i := ; i < ; i++ {
a = append(a, A{})
fmt.Printf("len=%d,cap=%d,ptr=%p\n", len(a), cap(a), p1)
} }

部分输出

Sizeof A: 40

len=1,cap=1,ptr=0xc00005c420

len=5,cap=5,ptr=0xc00005c420

len=6,cap=10,ptr=0xc00005c420

。。。

len=1638,cap=1638,ptr=0xc00005c420

len=1639,cap=2048,ptr=0xc00005c420

。。。

扩容分析
1、a = append(a, A{}, A{}, A{}, A{})
增加4个元素
原容量是1,元素个数增加了4个,不够存储需要扩容
newcap := old.cap //old.cap=>1
...
doublecap := newcap + newcap //2
if cap > doublecap {//cap=>5 实际的容量是5,大于2,新容量取值5
  newcap = cap
}
//Sizeof A: 40
数据类型的size是40个字节
走switch的
default:
  lenmem = uintptr(old.len) * et.size
  newlenmem = uintptr(cap) * et.size
  capmem, overflow = math.MulUintptr(et.size, uintptr(newcap)) //这里capmem=et.size*newcap即40*5=200
  //    14        208        8192       39          80      8.12%

  capmem = roundupsize(capmem)//内存对齐向上取整 为208
  newcap = int(capmem / et.size) //208/40=5
  新容量为5
  len=5,cap=5,ptr=0xc00005c420   2、看一下由1638扩容到2048的情况
  先看结果
  

  len=1638,cap=1638,ptr=0xc00005c420

  len=1639,cap=2048,ptr=0xc00005c42

  分析:

  数据类型size=40

 
    newcap := old.cap //先取用old.cap =>1638
doublecap := newcap + newcap //1638+1638=3276
if cap > doublecap { //cap是元素实际个数为1639
newcap = cap
} else {
if old.len < {//old.len=1638大于1024
newcap = doublecap
} else {
// Check 0 < newcap to detect overflow
// and prevent an infinite loop.
for < newcap && newcap < cap { //符合这个条件,扩容到1.25倍=>2047
newcap += newcap /
}
// Set newcap to the requested cap when
// the newcap calculation overflowed.
if newcap <= {
newcap = cap
}
}
}
.... default:
lenmem = uintptr(old.len) * et.size
newlenmem = uintptr(cap) * et.size
capmem, overflow = math.MulUintptr(et.size, uintptr(newcap)) //capmem=2047*40 =>81880
capmem = roundupsize(capmem) //内存对齐取整到81920
newcap = int(capmem / et.size) //81920/40=2048 //取整代码
func roundupsize(size uintptr) uintptr {
if size < _MaxSmallSize {
if size <= smallSizeMax- {
return uintptr(class_to_size[size_to_class8[(size+smallSizeDiv-)/smallSizeDiv]])
} else {
return uintptr(class_to_size[size_to_class128[(size-smallSizeMax+largeSizeDiv-)/largeSizeDiv]])
}
}
if size+_PageSize < size {
return size
}
return round(size, _PageSize) //=>81920
} func round(n, a uintptr) uintptr {
return (n + a - ) &^ (a - )
} size是81880大于_MaxSmallSize = //源码中定义的常量 _PageShift =
_PageSize = << _PageShift //1<<13 =>8192
 

参考链接

https://www.jianshu.com/p/303daad705a3

slice扩容的更多相关文章

  1. Go slice 扩容机制分析

    前言 我们都知道 Go 语言中的 slice 具有动态扩容的机制(不知道的同学请先补课 Go 切片) 但是其底层机制是什么呢?本着知其然,知其所以然的探索精神去研究一番.还不是为了应试 手动狗头 go ...

  2. 【Go】slice的一些使用技巧

    原文链接:https://blog.thinkeridea.com/201901/go/slice_de_yi_xie_shi_yong_ji_qiao.html slice 是 Go 语言十分重要的 ...

  3. golang中,slice的几个易混淆点

    slice在golang中是最常用的类型,一般可以把它作为数组使用,但是比数组要高效呀.不过,我感觉这个东西用的不好坑太多了.还是需要了解下他底层的实现 slice的结构定义 type slice s ...

  4. Go 语言入门 3-动态数组(slice)的特性及实现原理

    go 语言中的动态数组(slice),是基于数组实现的,可以相比数组而言更加的灵活.其他语言的 slice 通常仅是一个 API, 但是 go 语言的 slice 不仅仅是一种操作, 也是一种数据结构 ...

  5. Go指南_切片的长度与容量

    源地址 https://tour.go-zh.org/moretypes/11 一.描述 切片拥有 长度 和 容量. 切片的长度就是它所包含的元素个数. 切片的容量是从它的第一个元素开始数,到其底层数 ...

  6. golang一些知识点

    2.冒泡排序(二维数组使用): func main() { i := 1 MYLABEL: for { i++ if i > 3 { break MYLABEL } } fmt.Println( ...

  7. 万级K8s集群背后etcd稳定性及性能优化实践

    背景与挑战 随着腾讯自研上云及公有云用户的迅速增长,一方面,腾讯云容器服务TKE服务数量和核数大幅增长, 另一方面我们提供的容器服务类型(TKE托管及独立集群.EKS弹性集群.edge边缘计算集群.m ...

  8. go-slice实现的使用和基本原理

    目录 摘要 Slice数据结构 使用make创建Slice 使用数组创建Slice Slice 扩容 Slice Copy 特殊切片 总结 参考 你的鼓励也是我创作的动力 Posted by 微博@Y ...

  9. 排查golang的性能问题 go pprof 实践

    小结: 1.内存消耗分析 list peek  定位到函数   https://mp.weixin.qq.com/s/_LovnIqJYAuDpTm2QmUgrA 使用pprof和go-torch排查 ...

随机推荐

  1. 相关与卷积(数字信号处理)的数学原理及 Python 实现

    数学原理 在数字信号处理中,相关(correlation)可以分为互相关(cross correlation)和自相关(auto-correlation). 互相关是两个数字序列之间的运算:自相关是单 ...

  2. FileStream对文本进行读写操作

    class FileHelper { /// <summary> /// 检验文件路径是否合法 /// </summary> /// <param name=" ...

  3. [C++] 用Xcode来写C++程序[7] Class

    用Xcode来写C++程序[7] Class 不带构造函数的Rectangle类 // // Rectangle.h // Plus // // Created by YouXianMing on 1 ...

  4. Programming Assignment 5: Burrows–Wheeler Data Compression

    编程作业五 作业链接:Burrows-Wheeler Data Compression & Checklist 我的代码:MoveToFront.java & CircularSuff ...

  5. jquery ajax跨域解决

    双十一开发了一个抽奖API,最近上线了,各个事业部的大神们需要前台页面,异步调用我的抽奖API,要我提供js. js 提供之后发现不对,跨域了.之前也碰到过跨域的问题,研究过这个问题,三种方法解决. ...

  6. 【转载】 socket recv 和 read

    转自: http://blog.csdn.net/rankun1/article/details/50488989 send函数工作原理: send函数只负责将数据提交给协议层. 当调用该函数时,se ...

  7. 2.3 Python语言基础

    2.3 Python语言基础 1 语言语义(Language Semantics) 缩进,而不是括号 Python使用空格(tabs or spaces)来组织代码结构,而不是像R,C++,Java那 ...

  8. [SDOI2010]Hide and Seek

    题目 非常显然就是求一下距离每一个点曼哈顿距离最近的点和最远的点就好了 最远点非常好算,我们建完\(kd-tree\)之后直接暴力就好了 找最近点的时候会有这样一个问题,就是自己找到了自己 所以我们需 ...

  9. 【洛谷】【线段树】P3353 在你窗外闪耀的星星

    [题目描述:] /* 飞逝的的时光不会模糊我对你的记忆.难以相信从我第一次见到你以来已经过去了3年.我仍然还生动地记得,3年前,在美丽的集美中学,从我看到你微笑着走出教室,你将头向后仰,柔和的晚霞照耀 ...

  10. P3694 邦邦的大合唱站队

    题目背景 BanG Dream!里的所有偶像乐队要一起大合唱,不过在排队上出了一些问题. 题目描述 N个偶像排成一列,他们来自M个不同的乐队.每个团队至少有一个偶像. 现在要求重新安排队列,使来自同一 ...