Previously, I wrote an article about the runtime.SetFinalizer
that is used to be called when an object is cleaned up, but some issues with this function cause it to be used less frequently.
https://github.com/golang/go/issues/67535
SetFinalizer
must always refer to the first word of an allocation. This means programmers must know what an ‘allocation’ is, whereas that distinction isn’t generally exposed in the language.- There cannot be more than one finalizer on any object.
- Objects with finalizers involved in any reference cycle will silently fail to be freed, and the finalizer will never run.
- Objects with finalizers require at least two GC cycles to be freed.
For the above reasons, a new function runtime.AddCleanUp
has been added in Golang 1.24
to replace runtime.SetFinalizer
.
Neither runtime.AddCleanup
nor runtime.SetFinalizer
is guaranteed to execute.
The design goal of AddCleanup is to address many of the problems with runtime.SetFinalizer
, in particular avoids object resurrection, thus allowing for the timely cleanup of objects, and supporting cyclic cleanup of objects.
API
|
|
Based on this, a Demo for RAII (Resource Acquisition Is Initialization) can be written. In the go weak
article, we implemented a fixed-length cache
, changed the code a bit, add a newElemWeak
method that automatically calls delete
to remove the key
from the cache
when the oldest elem
is evicted. We don’t need to manage it manually.
|
|
A Few Things to Keep in Mind
AddCleanup
places a few constraints on ptr
and supports attaching multiple cleanup functions to the same pointer. However, if ptr
is reachable from cleanup
or arg
, it will never be reclaimed (memory leak), and the cleanup function will never run. For the moment, this scenario doesn’t pan out. However, a pattern like GODEBUG=gccheckmark=1
may detect this in the future.
For example
https://gist.github.com/hxzhouh/5bb1d55259dcb4dab87b37beaef9bea2
fmt.Println("close f")
will not be printed, and the file will not be closed.
When binding multiple cleanups
to a single ptr
, its running order may be variable since cleanup runs in a separate goroutine
.
In particular, if several objects point to each other and become unreachable simultaneously, their cleanup functions can all be run and in any order. This is true even if the objects form a loop (runtime.SetFinalizer
creates a memory leak in this case).
for example
https://gist.github.com/hxzhouh/ca402c723faa78726baba7e56bff573a