4

首先我们来看一段代码:

package main
import (
  "fmt"
  "unsafe"
)
func main() {
  var a int
  var b int8
  var c int16
  var d int32
  var e int64
  slice := make([]int, 0)
  slice = append(slice, 1)
  fmt.Printf("int:%dnint8:%dnint16:%dnint32:%dnint64:%dn", unsafe.Sizeof(a), unsafe.Sizeof(b), unsafe.Sizeof(c), unsafe.Sizeof(d), unsafe.Sizeof(e))
  fmt.Printf("slice:%d", unsafe.Sizeof(slice))
}

该程序输出golang中常用数据类型占多少byte,输出结果是:

int:8
int8:1
int16:2
int32:4
int64:8
slice:24

我们可以看到slice占24byte,为什么会占24byte,这就跟slice底层定义的结构有关,我们在golang的runtime/slice.go中可以找到slice的结构定义,如下:

type slice struct {
  array unsafe.Pointer//指向底层数组的指针
  len   int//切片的长度
  cap   int//切片的容量
}

我们可以看到slice中定义了三个变量,一个是指向底层数字的指针array,另外两个是切片的长度len和切片的容量cap。

slice初始化


简单了解了slice的底层结构后,我们来看下slice的初始化,在golang中slice有多重初始化方式,在这里我们就不一一介绍了,我们主要关注slice在底层是如何初始化的,首先我们来看一段代码:

package main
import "fmt"
func main() {
  slice := make([]int, 0)
  slice = append(slice, 1)
  fmt.Println(slice, len(slice), cap(slice))
}

很简单的一段代码,make一个slice,往slice中append一个一个1,打印slice内容,长度和容量,接下来我们利用gotool提供的工具将以上代码反汇编:

go tool compile -S slice.go

得到汇编代码如下(截取部分):

0x0000 00000 (slice.go:8)  TEXT  "".main(SB), ABIInternal, $152-0
  0x0000 00000 (slice.go:8)  MOVQ  (TLS), CX
  0x0009 00009 (slice.go:8)  LEAQ  -24(SP), AX
  0x000e 00014 (slice.go:8)  CMPQ  AX, 16(CX)
  0x0012 00018 (slice.go:8)  JLS  375
  0x0018 00024 (slice.go:8)  SUBQ  $152, SP
  0x001f 00031 (slice.go:8)  MOVQ  BP, 144(SP)
  0x0027 00039 (slice.go:8)  LEAQ  144(SP), BP
  0x002f 00047 (slice.go:8)  FUNCDATA  $0, gclocals- f14a5bc6d08bc46424827f54d2e3f8ed(SB)//编译器产生,用于保存一些垃圾收集相关的信息
  0x002f 00047 (slice.go:8)  FUNCDATA  $1, gclocals- 3e7bd269c75edba02eda3b9069a96409(SB)
  0x002f 00047 (slice.go:8)  FUNCDATA  $2, gclocals- f6aec3988379d2bd21c69c093370a150(SB)
  0x002f 00047 (slice.go:8)  FUNCDATA  $3, "".main.stkobj(SB)
  0x002f 00047 (slice.go:9)  PCDATA  $0, $1
  0x002f 00047 (slice.go:9)  PCDATA  $1, $0
  0x002f 00047 (slice.go:9)  LEAQ  type.int(SB), AX
  0x0036 00054 (slice.go:9)  PCDATA  $0, $0
  0x0036 00054 (slice.go:9)  MOVQ  AX, (SP)
  0x003a 00058 (slice.go:9)  XORPS  X0, X0
  0x003d 00061 (slice.go:9)  MOVUPS  X0, 8(SP)
  0x0042 00066 (slice.go:9)  CALL  runtime.makeslice(SB)//初始化slice
  0x0047 00071 (slice.go:9)  PCDATA  $0, $1
  0x0047 00071 (slice.go:9)  MOVQ  24(SP), AX
  0x004c 00076 (slice.go:10)  PCDATA  $0, $2
  0x004c 00076 (slice.go:10)  LEAQ  type.int(SB), CX
  0x0053 00083 (slice.go:10)  PCDATA  $0, $1
  0x0053 00083 (slice.go:10)  MOVQ  CX, (SP)
  0x0057 00087 (slice.go:10)  PCDATA  $0, $0
  0x0057 00087 (slice.go:10)  MOVQ  AX, 8(SP)
  0x005c 00092 (slice.go:10)  XORPS  X0, X0
  0x005f 00095 (slice.go:10)  MOVUPS  X0, 16(SP)
  0x0064 00100 (slice.go:10)  MOVQ  $1, 32(SP)
  0x006d 00109 (slice.go:10)  CALL  runtime.growslice(SB)//append操作
  0x0072 00114 (slice.go:10)  PCDATA  $0, $1
  0x0072 00114 (slice.go:10)  MOVQ  40(SP), AX
  0x0077 00119 (slice.go:10)  MOVQ  48(SP), CX
  0x007c 00124 (slice.go:10)  MOVQ  56(SP), DX
  0x0081 00129 (slice.go:10)  MOVQ  DX, "".slice.cap+72(SP)
  0x0086 00134 (slice.go:10)  MOVQ  $1, (AX)
  0x008d 00141 (slice.go:11)  PCDATA  $0, $0
  0x008d 00141 (slice.go:11)  MOVQ  AX, (SP)
  0x0091 00145 (slice.go:10)  LEAQ  1(CX), AX
  0x0095 00149 (slice.go:10)  MOVQ  AX, "".slice.len+64(SP)
  0x009a 00154 (slice.go:11)  MOVQ  AX, 8(SP)
  0x009f 00159 (slice.go:11)  MOVQ  DX, 16(SP)
  0x00a4 00164 (slice.go:11)  CALL  runtime.convTslice(SB)//类型转换
  0x00a9 00169 (slice.go:11)  PCDATA  $0, $1
  0x00a9 00169 (slice.go:11)  MOVQ  24(SP), AX
  0x00ae 00174 (slice.go:11)  PCDATA  $0, $0
  0x00ae 00174 (slice.go:11)  PCDATA  $1, $1
  0x00ae 00174 (slice.go:11)  MOVQ  AX, ""..autotmp_33+88(SP)
  0x00b3 00179 (slice.go:11)  MOVQ  "".slice.len+64(SP), CX
  0x00b8 00184 (slice.go:11)  MOVQ  CX, (SP)
  0x00bc 00188 (slice.go:11)  CALL  runtime.convT64(SB)
  0x00c1 00193 (slice.go:11)  PCDATA  $0, $1
  0x00c1 00193 (slice.go:11)  MOVQ  8(SP), AX
  0x00c6 00198 (slice.go:11)  PCDATA  $0, $0
  0x00c6 00198 (slice.go:11)  PCDATA  $1, $2
  0x00c6 00198 (slice.go:11)  MOVQ  AX, ""..autotmp_34+80(SP)
  0x00cb 00203 (slice.go:11)  MOVQ  "".slice.cap+72(SP), CX
  0x00d0 00208 (slice.go:11)  MOVQ  CX, (SP)
  0x00d4 00212 (slice.go:11)  CALL  runtime.convT64(SB)
  0x00d9 00217 (slice.go:11)  PCDATA  $0, $1
  0x00d9 00217 (slice.go:11)  MOVQ  8(SP), AX
  0x00de 00222 (slice.go:11)  PCDATA  $1, $3
  0x00de 00222 (slice.go:11)  XORPS  X0, X0

大家可能看到这里有点蒙,这是在干啥,其实我们只需要关注一些关键的信息就好了,主要是这几行:

查看完整版(【golang】slice源码分析)



去去1002
249 声望51 粉丝

去去