Groups keyboard shortcuts have been updated
Dismiss
See shortcuts

How to use weak pointers?

366 views
Skip to first unread message

Val Deleplace

unread,
Apr 7, 2025, 11:22:14 AMApr 7
to golang-nuts
"The primary use-cases for weak pointers are for implementing caches"

I'm trying to create objects and insert a weak pointer to each of them in a slice. The slice then contains the only reference to each object, thus it is possible for each pointer's value to become nil anytime, and the objects' memory garbage collected.

In practice, on my laptop (macOS, go 1.24.1) the weak pointers tend to become nil very fast, before I'm finished inserting 400 objects in the slice, which seems to be "as soon as the object becomes unreachable".  While this observation is consistent with the documentation, I'm wondering how I can effectively build a cache when the data tends to go away as soon as it is inserted?

Here is my code, which behaves a bit differently in the playground but the general observation remains.

robert engels

unread,
Apr 7, 2025, 12:03:59 PMApr 7
to Val Deleplace, golang-nuts
I think the documentation is incorrect.

Normally, weak pointers are used to break retain cycles in a system that uses references to implement garbage collection. Since Go has a tracing GC this isn’t necessary.

Usually, a “soft” reference, not a “weak” reference is used to implement caches. A “soft” reference being one that the GC can free if memory is needed and it is otherwise unreachable - but typically only releases it under memory pressure.

With a tracing GC, weak references are typically more useful for canonicalized maps - that is given a key you always want to return the same instance of the object, but if there are no longer any references to the object, the key (and value) can be removed from the map - which is sort of a cache, but not in the widely used sense.

With Go, implementing a LRU+ cache using standard references is typically all that is needed.

--
You received this message because you are subscribed to the Google Groups "golang-nuts" group.
To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts...@googlegroups.com.
To view this discussion visit https://groups.google.com/d/msgid/golang-nuts/1a129699-ce4a-4deb-bb83-ea2fa484d83bn%40googlegroups.com.

Michael Knyszek

unread,
Apr 14, 2025, 11:46:52 AMApr 14
to golang-nuts
I think it depends on your definition of cache. Caching the result of some computation that is related to the lifetime of a variable (but for any number of reasons needs to be decoupled from it) isn't necessarily a canonicalization map, but weak pointers may still be the right tool. I'm not sure what else to call such use-cases. (I originally agreed with Robert and I was originally much more specific in the documentation, but I think others were right that "cache" can cover a lot of other valid use-cases.)

On Monday, April 7, 2025 at 12:03:59 PM UTC-4 robert engels wrote:
I think the documentation is incorrect.

Normally, weak pointers are used to break retain cycles in a system that uses references to implement garbage collection. Since Go has a tracing GC this isn’t necessary.

Usually, a “soft” reference, not a “weak” reference is used to implement caches. A “soft” reference being one that the GC can free if memory is needed and it is otherwise unreachable - but typically only releases it under memory pressure.

With a tracing GC, weak references are typically more useful for canonicalized maps - that is given a key you always want to return the same instance of the object, but if there are no longer any references to the object, the key (and value) can be removed from the map - which is sort of a cache, but not in the widely used sense.

With Go, implementing a LRU+ cache using standard references is typically all that is needed.
+1. For the "backend web service" sense of cache, this is completely correct. It's not really intended for that kind of cache. I suppose the docs could call that out more clearly. 

On Apr 7, 2025, at 10:21 AM, Val Deleplace <delepl...@gmail.com> wrote:

"The primary use-cases for weak pointers are for implementing caches"

I'm trying to create objects and insert a weak pointer to each of them in a slice. The slice then contains the only reference to each object, thus it is possible for each pointer's value to become nil anytime, and the objects' memory garbage collected.

In practice, on my laptop (macOS, go 1.24.1) the weak pointers tend to become nil very fast, before I'm finished inserting 400 objects in the slice, which seems to be "as soon as the object becomes unreachable".  While this observation is consistent with the documentation, I'm wondering how I can effectively build a cache when the data tends to go away as soon as it is inserted?
Keep in mind that if that's *all* your program is doing, you're going to hit GC cycles quite quickly which will quickly collect everything. Context matters a lot here.

Val Deleplace

unread,
May 6, 2025, 1:28:04 PMMay 6
to golang-nuts
Thanks Robert and Michael, this is helpful.
I think my use case falls in the "backend web service" sense of cache category, and should probably not rely on weak pointers.

For me the appeal was "Build a cache without worrying about capacity. Let random items vanish when the runtime is getting short on memory". It's probably wiser however to build a cache with explicit limits on size, and implement my own eviction logic like LRU. My backend might run on a 512MB VM, or 1GB, or 2GB, so I'll have to figure out the appropriate cache size, depending on the current VM.

Reply all
Reply to author
Forward
0 new messages