Go 1.7 beta 1 was released this morning, here is the release notes draft of Go 1.7. A new function KeepAlive
was added to the package runtime
. The
A variable becomes unreachable when the runtime detects that the Go code cannot reach a point where that variable is referenced again.
In the example you posted, a syscall.Open() is used to open a file. The returned file descriptor (which is just an int
value) is "wrapped" in a struct
. Then a finalizer is attached to this struct value that closes the file descriptor. Now when this struct value becomes unreachable, its finalizer may be run at any moment, and the closing / invalidation / re-using of the file descriptor could cause unexpected behavior or errors in the execution of the Read()
syscall.
The last use of this struct value p
in Go code is when syscall.Read()
is invoked (and the file descriptor p.d
is passed to it). The implementation of the syscall will use that file descriptor after the initiation of syscall.Read()
, it may do so up until syscall.Read()
returns. But this use of the file descriptor is "independent" of the Go code.
So the struct value p
is not used during the execution of the syscall, and the syscall blocks the Go code until it returns. Which means the Go runtime is allowed to mark p
as unreachable during the execution of Read()
(before Read()
returns), or even before its actual execution begins (because p
is only used to provide the arguments to call Read()
.
Hence the call to runtime.KeepAlive(): since this call is after the syscall.Read()
and it references the variable p
, the Go runtime is not allowed to mark p
unreachable before Read()
returns, because this is after the Read()
call.
Note that you could use other constructs to "keep p
alive", e.g. _ = p
or returning it. runtime.KeepAlive()
does nothing magical in the background, its implementation is:
func KeepAlive(interface{}) {}
runtime.KeepAlive()
does provide a much better alternative because:
p
alive (to prevent runs of Finalizers)._ = p
might get "optimized" out by future compilers, but not runtime.KeepAlive()
calls.