597 字
3 分钟
Go 语言学习笔记 -第18章
Go 语言学习笔记 -第18章
堆空间&栈空间
在讲Go的堆栈之前,先温习一下堆栈基础知识。
什么是堆栈?在计算机中堆栈的概念分为:数据结构的堆栈和内存分配中堆栈。
堆栈跟踪
使用的go 版本是go 1.13.1
例子:
package main
import "runtime/debug"
func main() { slice := make([]string, 2, 4) Example(slice, "hello", 10)}func Example(slice []string, str string, i int) { debug.PrintStack()}运行结果:
goroutine 1 [running]:runtime/debug.Stack(0xc000041f50, 0xc000099f50, 0x404dd6) c:/go/src/runtime/debug/stack.go:24 +0xa4runtime/debug.PrintStack() c:/go/src/runtime/debug/stack.go:16 +0x29main.Example(...) d:/学习/golang/example/main.go:10main.main() d:/学习/golang/example/main.go:7 +0x28Process exiting with code: 0堆栈跟踪信息: 第一行显示运行的goroutine是id为 1的goroutine。
第二行 debug.Stack()被调用
第四行 debug.PrintStack() 被调用
第六行 调用debug.PrintStack()的代码位置,位于main package下的Example函数。它也显示了代码所在的文件和路径,以及debug.PrintStack()发生的行数(第10行)。
第八行 也调用Example的函数的名字,它是main package的main函数。它也显示了文件名和路径,以及调用Example函数的行数。
变量判断
变量是堆(heap)还是堆栈(stack)?
在当前的编译器中,如果变量具有其地址,则该变量是堆上分配的候选变量。 但是,基础的逃逸分析可以将那些生存不超过函数返回值的变量识别出来,并且因此可以分配在栈上。
Go的编译器会决定在哪(堆or栈)分配内存,保证程序的正确性。
下面通过反汇编查看具体内存分配情况:
新建 main.go
package main
import "fmt"
func main() { var a [1]int c := a[:] fmt.Println(c)}查看汇编代码
go tool compile -S main.go输出:
... 0x0028 00040 (main.go:5) FUNCDATA $2, gclocals·bfec7e55b3f043d1941c093912808913(SB) 0x0028 00040 (main.go:5) FUNCDATA $3, "".main.stkobj(SB) 0x0028 00040 (main.go:6) PCDATA $0, $1 0x0028 00040 (main.go:6) PCDATA $1, $0 0x0028 00040 (main.go:6) LEAQ type.[1]int(SB), AX 0x002f 00047 (main.go:6) PCDATA $0, $0 0x002f 00047 (main.go:6) MOVQ AX, (SP) 0x0033 00051 (main.go:6) CALL runtime.newobject(SB) 0x0038 00056 (main.go:6) PCDATA $0, $1 ...注意到有调用newobject!其中main.go:6说明变量a的内存是在堆上分配的!
修改main.go
package main
func main() { var a [1]int c := a[:] println(c)}再看汇编代码:
没有发现调用newobject,这段代码a是在堆栈上分配的。
结论:
Go 编译器自行决定变量分配在堆栈或堆上,以保证程序的正确性。
Go 语言学习笔记 -第18章
https://blog.zhequtao.com/posts/golang/go-learning/学习笔记-go/第18章/