我正在学习 Go 的内存管理和垃圾收集,当指针指向的变量超出范围后尝试取消引用指针时遇到了一些意外行为。
在 Go 中,我知道垃圾回收 (GC) 是自动的,并且指针有时会引用不再有效的内存。我预计取消引用指向范围外变量的指针会引发错误,但 Go 似乎不会在这样做时引发错误
这是一个演示该问题的最小示例:
package main
import (
"fmt"
"runtime"
)
func main() {
var p *int
{
x := 42
p = &x // p points to x
fmt.Println(*p) // Prints 42
}
// Force garbage collection (for testing)
runtime.GC()
// Dereferencing p here should cause an error (since x is out of scope)
fmt.Println(*p) // This does NOT throw any error
}
我的预期是:
- 我预计在 x 超出范围的内部块之后,指针 p 将成为一个“悬垂指针”,并且在取消引用时会立即导致运行时错误。
- 我预期的错误是这样的:运行时:无效的内存地址或空指针取消引用。
实际情况:
- 即使在强制垃圾回收后,程序在取消引用 *p 时也不会崩溃或抛出错误。即使 x 超出范围,打印的值仍然是 x 的地址。
GC 不关心范围。它检查是否有指向内存对象的活动指针。就你的情况而言,至少有一个。
变量
x
可能超出范围,但p
实际上并非如此,它指向x
,并且有一个 goroutine 使用p
,因此x
不会被垃圾回收。函数返回后,它将准备好被回收,因为p
也将超出范围。