ThinkChat2.0新版上线,更智能更精彩,支持会话、画图、阅读、搜索等,送10W Token,即刻开启你的AI之旅 广告
># 内存逃逸 * 逃逸分析目的是决定内分配地址是栈还是堆 * 申请到 栈内存 好处:函数返回直接释放,不会引起垃圾回收,对性能没有影响。 * 申请到堆上面的内存才会引起垃圾回收,如果这个过程(特指垃圾回收不断被触发)过于高频就会导致 gc 压力过大,程序性能出问题 >### 常见内存逃逸情况 - **返回局部变量的地址**:当函数返回局部变量的地址时,该变量会逃逸到堆上。 - **闭包引用局部变量**:当闭包引用了局部变量时,这些变量会逃逸到堆上。 - **接口类型的使用**:接口类型的变量由于具体类型在编译时不确定,通常会导致逃逸。 - **动态数据结构**:如 `map`、`slice`、`chan` 等动态数据结构在堆上分配,如果它们包含的元素在使用中发生变化,也可能导致元素逃逸。 - **大对象的分配**:大的对象在栈上分配可能导致栈空间不足,编译器会将其分配到堆上。 - **指针间接访问**:指针间接访问的变量可能会逃逸,因为需要保证指针在函数返回后仍然有效。 - **变量的生命周期超出函数作用域**:当变量的生命周期超过函数作用域时,编译器会将其分配到堆上以确保其有效性。 >### go build -gcflags -m - 可以查看具体的逃逸分析结果 ~~~ package main import "fmt" func main() { s1 := make([]int, 0, 0) s2 := make(map[string]int) s2["1"] = 1 s3 := make(chan int, 0) s4 := new(int) var s5 interface{} s5 = "s5" // 匿名函数(Anonymous Functions)是指不需要命名的函数,可以在任何地方定义和调用 func(message string) { fmt.Println(message) }("Hello, World!") // 闭包(Closure)是指能够捕获并使用其外部作用域变量的匿名函数。 // 闭包能够记住并访问它的作用域,包括变量和常量,即使在其作用域之外调用时也能访问这些变量 add := func(a, b int) int { return a + b } s6 := add(3, 4) fmt.Println(s1, s2["1"], <-s3, *s4, s5, s6) } ~~~ ``` PS E:\work\_a> go build -gcflags -m main.go # command-line-arguments ./main.go:15:2: can inline main.func1 ./main.go:21:9: can inline main.func2 ./main.go:17:3: inlining call to main.func1 ./main.go:24:11: inlining call to main.func2 ./main.go:26:13: inlining call to fmt.Println ./main.go:17:3: inlining call to fmt.Println ./main.go:16:14: inlining call to fmt.Println ./main.go:6:12: make([]int, 0, 0) escapes to heap ./main.go:7:12: make(map[string]int) does not escape ./main.go:10:11: new(int) does not escape ./main.go:12:7: "s5" escapes to heap ./main.go:17:3: ... argument does not escape ./main.go:17:3: message escapes to heap ./main.go:21:9: func literal does not escape ./main.go:26:13: ... argument does not escape ./main.go:26:14: s1 escapes to heap ./main.go:26:20: s2["1"] escapes to heap ./main.go:26:27: <-s3 escapes to heap ./main.go:26:33: *s4 escapes to heap ./main.go:26:42: s6 escapes to heap ```