21 Golang语言变量生命周期

21 Go语言变量生命周期

参考链接

https://blog.csdn.net/FX677588/article/details/78421334

生命周期

  • 函数中的局部变量被外部指针指向访问时候,这时这个变量会逃逸出函数,在堆上分配内存
  • 当用new申请的内存空间赋值给函数内的局部变量的时候(没有被外部指针指向),这时该
  • 代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
package main

import "fmt"

var p * int

func main() {
tmp()

fmt.Println(" p =", p, " *p = ", *p)
}

func tmp() {

// 定义一个栈上的变量,查看地址空间
var base = 0
fmt.Println(" &base =", &base, " base =", base)

// i=num 会逃逸出函数,因为被外部的p指针指向访问了,在函数外仍然可以访问
var num int
num = 1
p = &num
fmt.Println("p = &num =", p, " *p =", *p)

// tp 不会逃逸出函数,因为没有外部变量指向访问
var tp = new(int)
*tp = 2
fmt.Println(" tp =", tp, " *tp =", *tp)
}

结果

本来打算在外面定义一个全局变量var itp int,用来存储new申请的内存空间的地址,然后把地址传递出去,再在main函数中做类型转换,访问这块内存空间,如果程序崩溃,则恰恰说明说明了tp没有逃逸出函数,思路如下:

itp = (int)tp ==> p2itp = (* int)itp

  • 第一个是拿到tp的内存地址空间,做类型转换的时候失败了编译器不允许这种操作,int32, int64, uint, uint32, uint64, uintptr都试过了也不行,通过这种方式拿到的地址没有产生指针指向访问所以变量的不会逃逸出函数
  • 第二个是拿到tp的值,再做类型转换,进行访问内存空间(读/写访问)如果程序崩溃掉了,则说明tp没有逃逸出函数
  • 不过上面的两步都不行,第一个虽然不能转换成功,但是可以通过fmt.Printf打印地址,可以得到地址值,然后再通过fmt.Scanf重新存储到变量itp中,但是第二步就不可以了,即使通过查内存的方式也无法验证,因为读取内存内容不一定引起程序的崩溃。必须通过读/写访问才可以完整的验证。