I want to implement a weak reference in Go such that I can use a finalizer to detect when a data structure is no longer required and be able to store/clean up data.
One way I have found to do it is to use a uintptr as a map key such that when a finalizer is called, I can access/cleanup the data using the pointer value passed to the finalizer function. Is this safe to do?
I think my question is: does Go use a moving garbage collector? Or will it?
The link that you yourself quoted in a comment provides the answer to the question you meant to ask: instead of giving clients a pointer to the underlying object that you'd like to fuss with, give them a pointer to a wrapper object:
type internal struct {
// all the internal stuff goes here
}
// change the name Wrapper below to something more suitable
type Wrapper struct {
*internal // or p *internal if you want to be overly verbose
}
func NewWhatever(/*args*/) *Wrapper {
p := &Wrapper{...} // fill this part in
runtime.SetFinalizer(p, wrapperGotCollected)
return p
}
func wrapperGotCollected(p *Wrapper) {
// since p itself is about to be collected,
// **p (or *((*p).p)) is no longer accessible by
// the user who called NewWhatever(). Do
// something appropriate here.
}
Note that this does not use a finalizer on the *internal
, but rather a finalizer on the *Wrapper
: at the time that wrapperGotCollected
is called, the *internal
object itself is guaranteed still to be live because p
itself has not yet been GC-ed (it's sort of halfway there, and will be the rest of the way there as soon as, or shortly after, wrapperGotCollected
returns).