Skip to content

Instantly share code, notes, and snippets.

@Snawoot
Last active May 12, 2025 20:29
Show Gist options
  • Save Snawoot/fc32d14b11af576c20bf5cc2c1cc8b25 to your computer and use it in GitHub Desktop.
Save Snawoot/fc32d14b11af576c20bf5cc2c1cc8b25 to your computer and use it in GitHub Desktop.

In our discussion yesterday, @bradfitz asked if weak pointers made it possible to maintain a map of expensive derived information about something without preventing the GC of that something. Here is a worked example of how weak pointer enables that:

var cache struct {
    mu sync.Mutex
    m map[weak.Pointer[Foo]]*derived
}

func init() {
    cache.m = make(map[weak.Pointer[Foo]]*derived)
}

func cached(f *Foo) *derived {
    cache.mu.Lock()
    defer cache.mu.Unlock()

    p := weak.Make(f)
    d := cache.m[p]
    if d != nil {
        return d
    }
    d = expensiveComputation(f)
    cache.m[p] = d
    runtime.AddCleanup(f, deleteP, p)
}

func deleteP(p weak.Pointer[Foo]) {
    cache.mu.Lock()
    defer cache.mu.Unlock()

    delete(cache.m, p)
}

I am assuming runtime.AddCleanup from #67535, which is guaranteed to work with any pointer f. (SetFinalizer might break things if f already had a finalizer, or if f was inside another object.)

-- @rsc golang/go#67552 (comment)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment