Fundamentals 14 min read

Weak Pointers Across Go, Rust, Java, and C#: Design, Implementation, and Use Cases

This article examines the concept of weak pointers and weak references in Go, Rust, Java, and C#, comparing their implementations, explaining their memory‑management semantics, presenting concrete code examples, and discussing the upcoming Go weak‑pointer proposal and practical scenarios such as caching and event handling.

BirdNest Tech Talk
BirdNest Tech Talk
BirdNest Tech Talk
Weak Pointers Across Go, Rust, Java, and C#: Design, Implementation, and Use Cases

The Go team introduced a unique package and simultaneously drafted two proposals: a weak package for weak pointers and a runtime change adding AddCleanup while deprecating SetFinalizer. The article first explains the weak pointer concept: a reference that does not prevent the garbage collector from reclaiming the referenced object, turning into nil when the object is collected, and can be upgraded to a strong pointer for safe access.

Other Languages' Weak Pointers

Rust

Rust provides std::rc::Weak paired with Rc for single‑threaded scenarios and std::sync::Weak paired with Arc for multi‑threaded contexts. Weak does not increase the reference count, avoiding cyclic references. It can be upgraded via upgrade(), returning Some(Rc) if the object still exists or None otherwise.

use std::rc::{Rc, Weak};

struct Node {
    value: i32,
    next: Option<Rc<Node>>,
    prev: Option<Weak<Node>>, // weak reference to prevent cycles
}

fn main() {
    let node1 = Rc::new(Node { value: 1, next: None, prev: None });
    let node2 = Rc::new(Node { value: 2, next: Some(Rc::clone(&node1)), prev: Some(Rc::downgrade(&node1)) });

    // Upgrade weak reference to access the previous node
    if let Some(prev_node) = node2.prev.as_ref().unwrap().upgrade() {
        println!("Previous node value: {}", prev_node.value);
    } else {
        println!("Previous node has been dropped");
    }
}

Java

Java uses java.lang.ref.WeakReference to hold a reference that the garbage collector may reclaim when no strong references exist. Weak references are useful for caches and listeners because the GC ignores them, preventing memory leaks. Access is via get(), which returns the strong reference if the object is still alive or null after collection.

import java.lang.ref.WeakReference;

public class WeakRefExample {
    public static void main(String[] args) {
        Object obj = new Object();
        WeakReference<Object> weakRef = new WeakReference<>(obj);
        obj = null; // drop strong reference
        if (weakRef.get() != null) {
            System.out.println("Object is still alive");
        } else {
            System.out.println("Object has been garbage collected");
        }
    }
}

C#

.NET provides WeakReference (and the generic WeakReference<T>) which allows an object to be referenced without preventing its collection. The Target property (or TryGetTarget) returns the strong reference when the object is alive, otherwise null. The IsAlive property can be used for a quick liveness check.

using System;

class Program {
    static void Main() {
        var obj = new object();
        WeakReference weakRef = new WeakReference(obj);
        obj = null; // drop strong reference
        if (weakRef.IsAlive) {
            Console.WriteLine("Object is still alive");
        } else {
            Console.WriteLine("Object has been garbage collected");
        }
    }
}

Go Weak‑Pointer Proposal

Michael Knyszek submitted a proposal that has been accepted and is expected to land in Go 1.24. The proposal defines a generic Pointer[T any] type with a Make constructor and a Value method that returns nil once the underlying object is reclaimed. Equality semantics are based on the original pointer, enabling weak‑pointer keys in maps.

// Pointer is a weak pointer to a value of type T.
// Equality is based on the original pointer, even after the object is collected.

type Pointer[T any] struct { ... }

// Make creates a weak pointer from a *T.
func Make[T any](ptr *T) Pointer[T] { ... }

// Value returns the original *T or nil if it has been collected.
func (p Pointer[T]) Value() *T { ... }

The implementation stores an 8‑byte allocation per weak pointer, allowing the garbage collector to atomically set the internal pointer to nil. This design incurs minimal overhead and preserves natural equality semantics, making it suitable for building maps keyed by weak pointers.

Common Use Cases for Weak References

Cache mechanisms : Use weak references to let the GC reclaim cached data when memory is scarce.

Event handlers and callbacks : Prevent memory leaks caused by strong references from listeners to their subjects.

Large object graphs : Break cycles in complex reference structures without manual cleanup.

Example: a cache that stores values behind weak pointers, automatically cleaning up entries when the underlying key is collected.

type Cache[K any, V any] struct {
    f func(*K) V
    m atomic.Map[weak.Pointer[K], func() V]
}

func NewCache[K comparable, V any](f func(*K) V) *Cache[K, V] {
    return &Cache[K, V]{f: f}
}

func (c *Cache[K, V]) Get(k *K) V {
    kw := weak.Make(k)
    if vf, ok := c.m.Load(kw); ok {
        return vf()
    }
    vf := sync.OnceValue(func() V { return c.f(k) })
    vf, loaded := c.m.LoadOrStore(kw, vf)
    if !loaded {
        runtime.AddCleanup(k, c.cleanup, kw)
    }
    return vf()
}

func (c *Cache[K, V]) cleanup(kw weak.Pointer[K]) {
    c.m.Delete(kw)
}

var cached = NewCache(expensiveComputation)

References:

unique package: https://pkg.go.dev/unique

weak proposal discussion: https://github.com/golang/go/issues/67552

runtime AddCleanup proposal: https://github.com/golang/go/issues/67535

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

JavaMemory ManagementRustGoGarbage CollectionCweak pointers
BirdNest Tech Talk
Written by

BirdNest Tech Talk

Author of the rpcx microservice framework, original book author, and chair of Baidu's Go CMC committee.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.