扩容的源码
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. android 自定义控件之ViewGroup生命周期执行步骤

    前言 了解ViewGroup的生命周期的执行步骤对于自己自定义ViewGroup的时候十分重要,清楚了整个流程才能对ViewGroup有更深的理解.本文从个人的总结,来阐述一下执行的顺序.执行说明 首 ...

  2. linux安装memcached

    一:为什么要使用memcached 瓶颈:互联网发展,特别在web2.0兴起之后,传统数据库开始出现瓶颈 1:对数据库的高并发读写 2:对海量数据库的处理(海量数据查找)memcache 是高性能的分 ...

  3. Jquery异步 Deferred Object

    Deferred Object )); return dtd.promise();};//使用$.when()为普通操作添加回调函数 为多个操作指定回调函数//$.when(deferred, def ...

  4. [UI] 精美UI界面欣赏[5]

    精美UI界面欣赏[5]

  5. 【matlab】 拉格朗日插值

    第一个函数  "lagrange1.m" 输入:X Y 与点x0 输出:插值函数对应函数值 y0 function y = lagrange1(X,Y,x0) n = length ...

  6. python---九九乘法表代码

    #_*_ coding:utf-8 _*_# author choco ''' #while循环num1=0while num1<9: num1+=1 num2=1 while num2< ...

  7. 微信小程序初始化 operateWXData:fail invalid scope

    初学者开发微信小程序,可以使用云开发来进行微信小程序的开发. 第一次使用开发工具遇到的问题 解决方案:1.找到云开发 2.点击开通,选择合适自己的开发环境: 3.完成后,返回开发工具界面点击项目第一个 ...

  8. PHP设计模式系列 - 策略模式

    策略模式: 策略模式设计帮助构建的对象不必自身包含逻辑,而是能够根据需要利用其他对象中的算法. 使用场景: 例如有一个CD类,我们类存储了CD的信息. 原先的时候,我们在CD类中直接调用getCD方法 ...

  9. python第十五课——全局变量and局部变量

    全局变量&局部变量: 全局变量的特点: 1).直接定义在.py文件中(函数外)的变量(全局位置) 2).作用域比较大,可以被此文件中的任何函数所使用 局部变量的特点:1).定义在函数内部(函数 ...

  10. 1927. [SDOI2010]星际竞速【费用流】

    Description 10年一度的银河系赛车大赛又要开始了.作为全银河最盛大的活动之一,夺得这个项目的冠军无疑是很多人的 梦想,来自杰森座α星的悠悠也是其中之一.赛车大赛的赛场由N颗行星和M条双向星 ...