Search code examples
gogarbage-collection

Is it safe to use a uintptr as a weak reference


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?


Solution

  • 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).