当运行时检测到 Go 代码无法到达再次引用该变量的位置时,变量将变得不可访问。
在您发布的示例中,a
syscall.Open()用于打开文件。返回的文件描述符(只是一个
int值)被“包装”在
struct。然后,将终结器附加到此结构值,以关闭文件描述符。现在,当此结构值变得不可访问时,其终结器可能随时运行,并且文件描述符的关闭/失效/重用可能会导致意外的行为或
Read()系统调用执行中的错误。
在一次使用这种结构值的
p在 围棋 代码时
syscall.Read()被调用(和文件描述符
p.d传递给它)。系统调用的实现将使用文件描述符后
开始 的
syscall.Read(),它可以这样做,直到
syscall.Read()回报。但是,文件描述符的这种使用与Go代码“无关”。
因此,
p在执行系统调用期间不会使用struct值,并且系统调用会阻塞Go代码,直到返回为止。这意味着Go运行时
p在执行过程中
Read()(
Read()返回之前)或
什至在其实际执行开始之前 被标记为不可访问(因为
p仅用于提供call的参数)
Read()。
因此,对
runtime.KeepAlive():的调用由于在该调用
之后 ,
syscall.Read()并且它 引用
了变量
p,因此不允许Go运行时
p在
Read()返回之前将其标记为不可访问,因为在
Read()调用之后。
请注意,您可以使用其他构造来“保持
p活动”,例如
_ = p返回它。
runtime.KeepAlive()在后台没有任何神奇的事情,其实现是:
func KeepAlive(interface{}) {}runtime.KeepAlive()确实提供了更好的选择,因为:
- 它清楚地记录了我们要保持
p
生存的状态(以防止Finalizer运行)。 - 使用其他结构(例如)
_ = p
可能会被将来的编译器“优化”,但不会被runtime.KeepAlive()
调用。



