Mastering Go 1.24 Weak References: Using the New std‑lib weak Package
This article explains Go 1.24's new std‑lib weak package, compares it with weak reference implementations in other languages, demonstrates its API with practical code examples, and shows how to build canonicalization maps and fixed‑size caches using weak pointers.
What is weak?
Go 1.24 adds a new standard‑library package weak that lets you create safe references ( *T) without preventing the referenced object from being reclaimed by the garbage collector.
Package weak provides ways to safely reference memory weakly, that is, without preventing its reclamation.
Like OS.ROOT, weak has existed in many other languages: Java: WeakReference and SoftReference for caches and object pools, reclaimed when the JVM is low on memory. Python: the weakref module for avoiding circular references and caching. C++: std::shared_ptr with std::weak_ptr to break reference cycles. Rust: Rc / Arc provide Weak references for similar purposes.
The weak API is simple: a Make method returns a weak.Pointer, and a Value method retrieves the original T or nil if it has been collected.
Example:
func main() {
originalObject := "Hello, World!"
runtime.AddCleanup(&originalObject, func(s int64) {
fmt.Println("originalObject clean at: ", s)
}, time.Now().Unix())
weakPtr := weak.Make(&originalObject)
fmt.Println(fmt.Sprintf("originalObject:addr %x", &originalObject))
fmt.Println(fmt.Sprintf("weakPtr addr:%x,size:%d", weakPtr, unsafe.Sizeof(weakPtr)))
runtime.GC()
time.Sleep(1 * time.Millisecond)
value := weakPtr.Value()
if value != nil && strings.Contains(*value, originalObject) {
fmt.Println("First GC :value: ", *value)
} else {
fmt.Println("first gc. Weak reference value is nil")
}
runtime.GC()
time.Sleep(1 * time.Millisecond)
value = weakPtr.Value()
if value != nil {
fmt.Println("Second GC", *value)
} else {
fmt.Println("Second GC: Weak reference value is nil")
}
}Running this program shows that after the first GC the weak reference still returns the string, but after the second GC it returns nil because the original object is no longer reachable.
The example also uses runtime.AddCleanup, a new Go 1.24 feature similar to runtime.SetFinalizer, which runs a callback when an object is collected. weak.Make creates an intermediate address ( weak.Printer) that hides the real pointer. weak.Printer does not prevent the real object from being reclaimed; if it is reclaimed, weak.Printer.Value returns nil. Therefore callers must always check the return value.
What can weak be used for?
Canonicalization maps
In Go 1.23 the unique feature deduplicated identical strings by storing a single pointer. Go 1.24 rewrites unique using weak, achieving a similar memory‑saving effect.
Fixed‑size cache
Below is a sketch of a fixed‑size cache that combines weak with list.List:
type WeakCache struct {
cache map[string]weak.Pointer[list.Element] // weak references to values
mu sync.Mutex
storage Storage
}
type Storage struct {
capacity int // maximum cache size
list *list.List
}
func (c *WeakCache) Set(key string, value any) {
// Update existing element if it still exists
if elem, exists := c.cache[key]; exists {
if elemValue := elem.Value(); elemValue != nil {
elemValue.Value = &CacheItem{key: key, value: value}
c.storage.list.MoveToFront(elemValue)
c.cache[key] = weak.Make(elemValue)
return
} else {
c.removeElement(key)
}
}
// Evict if capacity reached
if c.storage.list.Len() >= c.storage.capacity {
c.evict()
}
// Add new element
elem := c.storage.list.PushFront(&CacheItem{key: key, value: value})
c.cache[key] = weak.Make(elem)
}The full source is available at https://gist.github.com/hxzhouh/1945d4a1e5a6567f084628d60b63f125 . By storing cache entries as weak pointers, the cache automatically discards items that are no longer referenced elsewhere, enabling an efficient fixed‑size cache without explicit eviction logic.
In summary, Go's new weak package provides a simple API for creating weak references, useful for canonicalization, caches, and other scenarios where you want objects to be reclaimed automatically when no longer needed.
Further reading:
Go 1.24 weak package documentation
Discussion of weak references in Go
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
