Go 1.24 introduces a new std-lib package called weak, which allows you to create safe references to *T without preventing the garbage collector (GC) from reclaiming the memory associated with *T.
The
weakpackage provides ways to safely reference memory weakly without preventing the garbage collector’s reclamation.
Much like OS.ROOT, weak is a feature that has existed in other programming languages for some time, including:
- In
Java,WeakReferenceandSoftReferenceare classic implementations primarily used for caching and object pools. These references allow automatic garbage collection when the JVM detects a memory shortage. - In
Python, theweakrefmodule allows the creation of weak references, commonly used to prevent circular reference issues or for caching. - In
C++,std::weak_ptrwas introduced alongsidestd::shared_ptrto solve circular dependency problems with shared pointers. - In
Rust,Weakis the weak reference version ofRcandArc, which helps prevent circular references and provides more flexible memory management.
Simple Definition of weak
The weak package is defined, with just a Make method and a Value method.

By using weak.Make, a weak.Pointer is created, and if the original *T has not been GC, we can access its address through weak.Pointer.Value. If the object has been collected, the Value will return nil.
You can see an example implementation of weak here: Example Code on Gist
Example Output:
|
|
In this example:
- We create a
stringvariableoriginalObjectand useweak.Maketo create aweak.PointercalledweakPtr. - During the first garbage collection (GC), since
originalObjectis still in use,weakPtr.Valuereturns the address oforiginalObject. - In the second GC, since
originalObjectis no longer used, it is collected by the GC, andweakPtr.Valuereturnsnil.
Also, runtime.AddCleanup, a new feature in Go 1.24, works similarly to runtime.SetFinalizer by allowing you to execute code when an object is garbage collected. This feature will be covered in more detail in a later post.
Key Takeaways:
weak.Makecreates aweak.Pointer, which hides the real memory address but does not affect the GC.- If the real object is garbage collected,
weak.Pointer.Valuewill returnnil. Since we don’t know when the real object will be reclaimed, always check the return value ofweak.Pointer.Value.
The Practical Use of weak
Canonicalization Maps
You might remember the unique feature introduced in Go 1.23, which uses a single pointer (8 bytes) to represent multiple identical strings, saving memory. The weak package can achieve similar functionality (In fact, in Go 1.24, unique has been refactored using weak).
Implementing a Fixed-Size Cache
|
|
In this example, we use a fixed-size list and a Map to store the position of each key in the list, where the value is a weak.Pointer to a list.Element. When we add a new cache item, we first check if the list is full. If so, the oldest item is evicted. When a key exists in the cache, Map[key].Value will return the address of the list element. If the item is evicted, Map[key].Value returns nil.
This design helps to create an efficient, fixed-size cache system. Using weak with a lock-free queue structure allows for even more efficient data handling.
I find weak to be quite helpful in specific scenarios. It’s easy to use, and I plan to incorporate it into my projects.