advanced-go-programming-book icon indicating copy to clipboard operation
advanced-go-programming-book copied to clipboard

一个栈上变量会地址会更改的例子

Open widon1104 opened this issue 4 years ago • 2 comments

package main

var b *int

func main() {
	testStack()
}

func testStack() {
	var x int = 1
	//b = &x
	println(&x)
	testLargeX(&x)
	println(&x)
}

func testLargeX(x *int) {
	var a = make([]int, 2000)
	for i := 0; i < len(a); i++ {
		a[i] = 1
	}
	println(a[1])
	println(x, *x)
}

这个程序输出为: 0xc000042770 1 0xc000107f70 1 0xc000107f70 x这个栈上变量因为栈空间的扩张,栈在另一个地方重新分配内存,x的地址变化了

如果把注释的那行 b = &x放开 widon@widon-deepin:~/golang/src/test/stackTest$ go build -gcflags="-m" test/stackTest ./1.go:9:6: can inline testStack ./1.go:5:6: can inline main ./1.go:6:11: inlining call to testStack ./1.go:17:17: x does not escape ./1.go:18:14: make([]int, 2000) does not escape ./1.go:6:11: moved to heap: x ./1.go:10:6: moved to heap: x x就会在堆上分配内存,那x的地址就不会变化了

widon1104 avatar Apr 14 '20 08:04 widon1104

这个例子挺不错的

cch123 avatar Apr 14 '20 09:04 cch123

go build -gcflags="-m"

请问这个例子用的golang是什么什么版本?我这里得到的结果不太一样,1.14还是哪个版本之后,默认栈是8k了,我1.16试了下,2000字节到7k,指针打印的值都没变,改成8k,栈不够了,也是变量a(var a = make([]int, 1024*8)逃逸了、栈和栈变量地址没有改变:

0xc00003df68
1
0xc00003df68 1
0xc00003df68

7k内联逃逸情况:

go build -gcflags="-m" .\stack.go
# command-line-arguments
.\stack.go:17:6: can inline testLargeX
.\stack.go:9:6: can inline testStack
.\stack.go:13:12: inlining call to testLargeX
.\stack.go:5:6: can inline main
.\stack.go:6:11: inlining call to testStack
.\stack.go:6:11: inlining call to testLargeX
.\stack.go:6:11: make([]int, 1024 * 7) does not escape
.\stack.go:13:12: make([]int, 1024 * 7) does not escape
.\stack.go:17:17: x does not escape
.\stack.go:18:14: make([]int, 1024 * 7) does not escape

8k内联逃逸情况:

go build -gcflags="-m" .\stack.go
# command-line-arguments
.\stack.go:17:6: can inline testLargeX
.\stack.go:9:6: can inline testStack
.\stack.go:13:12: inlining call to testLargeX
.\stack.go:5:6: can inline main
.\stack.go:6:11: inlining call to testStack
.\stack.go:6:11: inlining call to testLargeX
.\stack.go:6:11: make([]int, 1024 * 8) escapes to heap
.\stack.go:13:12: make([]int, 1024 * 8) escapes to heap
.\stack.go:17:17: x does not escape
.\stack.go:18:14: make([]int, 1024 * 8) escapes to heap

而且单就楼主例子中的 make([]byte, 2000),go历史版本最小栈也有2048吧、但是得是非常老的版本了吧?而且即使老版本因为这2000而导致栈扩容,但是栈变量地址改变还需要栈扩容时原栈尾部没有空闲内存可用realloc才会触发,这个简单的例子想触发,应该得是比较特殊得环境才行吧?

lesismal avatar Jul 21 '21 12:07 lesismal