WeakRef Basics
A
WeakRef holds a weak reference to an object — it does not prevent garbage collection. deref() returns the object if it is still alive, or undefined if the GC has collected it.Step-by-step Demo
Code
// Create an object
let obj = { data: "important", size: 10000 };
// Create a weak reference
const ref = new WeakRef(obj);
// Access the object through WeakRef
const derefed = ref.deref();
// → { data: "important", size: 10000 }
// Drop the strong reference
obj = null;
// After GC (non-deterministic timing):
ref.deref(); // → undefined
Log
FinalizationRegistry
FinalizationRegistry lets you register a callback that fires after an object is garbage collected. The callback receives a held value (not the object itself, since it has been GC'd).Interactive Demo
Code
const registry = new FinalizationRegistry(heldValue => {
console.log(`Object "${heldValue}" was garbage collected`);
// Clean up: close connections, release resources, etc.
});
let obj = { name: "resource" };
const token = {}; // unregister token
registry.register(obj, "resource-id", token);
// Later, if you want to prevent the callback:
// registry.unregister(token);
obj = null; // Object is now eligible for GC
// Callback fires at some point after GC
Registry Events
WeakRef Cache Pattern
Use WeakRef to build caches that don't prevent GC. When cached objects are no longer referenced elsewhere, they can be collected, and the cache entry cleaned up via FinalizationRegistry.
WeakRef Cache Implementation
class WeakRefCache {
#cache = new Map();
#finRegistry = new FinalizationRegistry(key => {
const ref = this.#cache.get(key);
if (ref && !ref.deref()) this.#cache.delete(key);
});
set(key, value) {
this.#cache.set(key, new WeakRef(value));
this.#finRegistry.register(value, key);
}
get(key) {
const ref = this.#cache.get(key);
if (!ref) return undefined;
const obj = ref.deref();
if (!obj) { this.#cache.delete(key); return undefined; }
return obj;
}
get size() { return this.#cache.size; }
}
Cache Events
Object Lifecycle Visualization
Track an object through its lifecycle stages: creation, reference management, GC eligibility, and finalization.
Lifecycle Stages
Object Cards
Timeline
GC Pressure Simulation
Allocate many objects to pressure the garbage collector. Track how many WeakRefs survive after allocation bursts. GC behavior is engine-specific and non-deterministic.
Allocation Burst
Total allocated: 0
WeakRefs alive: 0
Finalization callbacks: 0
GC Events
Strong vs Weak Reference Comparison
Compare how strong references (Map, Set, variables) and weak references (WeakRef, WeakMap, WeakSet) affect object lifetime and garbage collection eligibility.
Side-by-side Comparison
| Aspect | Strong Reference | Weak Reference |
|---|---|---|
| Prevents GC | Yes — object stays alive | No — object can be collected |
| Access guarantee | Always available | May return undefined after GC |
| Memory pressure | Contributes to pressure | Does not contribute |
| Use case | Data you need to keep | Caches, metadata, observers |
| API | Variables, Map, Set, Array | WeakRef, WeakMap, WeakSet |
| Cleanup | Manual (delete, splice, clear) | Automatic via GC |
| Notification | N/A | FinalizationRegistry callback |
Interactive Demo
Log
Memory Leak Prevention Patterns
Common memory leak sources and how WeakRef/WeakMap/WeakSet help prevent them. These patterns are especially important for long-running applications.
Leak Scenarios
Pattern Analysis
Best Practices
- Use WeakMap for DOM node metadata — entries auto-clean when nodes are removed
- Use WeakSet to track visited/processed objects without preventing GC
- Use WeakRef for caches of expensive-to-create objects
- Use FinalizationRegistry for cleanup of external resources (file handles, connections)
- Never rely on finalization for correctness — GC timing is non-deterministic
- Don't use WeakRef where a strong reference is needed — deref() can return undefined at any time
- Prefer
AbortControllerfor event listener cleanup over WeakRef hacks