进程空间栈

栈和堆上内存分配与回收

变量和对象

1、变量声明和初始化

  • 第一种:var i int,此时只有零值0
  • 第二种:var i = 0,此时会自行判定为int,并赋初值为0
  • 第三种: i := 0,跟第二种类似
  • 第三种:var i int = 0,一般不这么写**

2、关于零值

  • 数值类型(包括complex64和complex128)零值为0,[complex64由一个float32表示实数和一个float32表示虚数,complex28用两个float64表示)
  • bool零值为false
  • string零值为””
  • nil可以作为interface、function、pointer、map、slice、channel的空值,如果不特别指定,go是无法识别类型,编译报错:cannot use nil as type xxx

3、go的多重赋值
go会先计算”=”左边的表达式,再计算右边的表达式,比如下面例子:

  1. i, j := 0, 0
  2. i, j = 1, i

结果是:

  1. i=1, j=0

4、go常量
go常量会在预编译阶段直接展开,作为指令数据使用,所以无法寻址;而变量则是在运行期间分配内存,可以正常寻址,能得到其地址或取其指针。例如:

  1. const i = 1
  2. var i = 123
  3. fmt.Println(&i, &j)
  1. 会报错:cannot take the address of i

因为i是常量

5、go值类型和引用类型

6、go对象

  • map对象:

底层由两个hashmap构成,map因为会动态扩容,导致其value内存地址可能会变,所以map的value不能寻址,不能通过&获取地址,也就不能直接进行单独赋值,除非用临时变量或者value指针表示。

  1. type Person struct {
  2. age int
  3. }
  4. var m = map[int]Person{
  5. 1: Person{age: 20},
  6. }
  7. m[1].age = 30

可以用一下方式替换:

  1. // 1.指针方式
  2. var m = map[int]*Person{
  3. 1: &Person{age: 20},
  4. }
  5. m[1].age = 30
  6. // 2.临时变量覆盖
  7. var m = map[int]Person{
  8. 1: Person{age: 20},
  9. }
  10. person := Person{age: 30}
  11. m[1] = person

另外因为go的运行时决定了,在gc时,不能让外部持有变量的内部变量的指针,所以map的键值不能寻址。

7、不可寻址的类型
不可寻址意思是不能用&取其地址,即不能改变其值,满足以下三个条件之一就不能寻址。

  • 不可变的:常量和基本类型的字面量会存储在固定区域
  • 临时结果:对字面量施加的表达式的求值结果都看作是临时结果

    获得某个元素的索引表达式 获得某个切片(片段)的切片表达式 访问某个字段的选择表达式

调用某个函数或方法的调用表达式

转换值的类型的类型转换表达式

判断值的类型的类型断言表达式

向通道发送元素或从通道哪里接收元素值的接收表达式

  • 不安全的

map的键值的地址可能会变,对其取地址,会破坏map的一致性

new和make

1、new
内建函数:func new(Type) *Type
理解为只分配内存

new只有一个参数,返回的是指向变量的类型指针

2、make
内建函数:func make(Type, size …IntegerType) Type
只适用于初始化slice map或channel

所以make至少有2个参数,按指定大小初始化变量类型,返回的是变量的引用类型【该引用类型的指向的值就是变量的实际value的地址,也可以把这个地址叫指针】
如:make([]int, 10),初始化一个len=10,cap=10的slice【注意cap>=len,否则编译报错】

make(slice)返回的是切片对象,是一个实体
make(map)返回的是map指针

3、比较
从上面定义和比较看出
new可以给一切支持的变量类型分配内存,如果new的是复杂类型(map slice chan),此时也只生成了指向变量的指针(或叫地址1),而变量指向实际值的指针(或叫地址2)还是nil
而make只针对涉及到多个元素个数的这种复杂变量类型(map slice chan),按指定的长度初始化变量,因为返回的是引用,所以该引用是直接指向的变量内存块,该内存块中指向实际值的指针(或叫地址2)不是nil,而是指向了已初始化的数据,虽然可能是空值
如下图:
image.png

变量逃逸

gc