Lesson 28: Mastering JavaScript Garbage Collection with challenges!

🚀 What is Garbage Collection?
Garbage Collection (GC) is JavaScript’s built-in memory cleanup mechanism. It automatically reclaims memory occupied by objects no longer “reachable” or “in use,” helping prevent memory leaks.
🧠 Key Principle: Reachability
JS only keeps values in memory if they’re reachable from the “roots.”
Roots include:
Global variables
The current execution context (stack)
Closures in active functions
✅ If an object is not reachable → It’s garbage → GC removes it.
📦 Example 1: Simple Reference Loss
let user = { name: "John" };
user = null; // 'John' is now unreachable and collected
🔗 Example 2: Two References
let user = { name: "Ann" };
let admin = user;
user = null; // Object still reachable via 'admin'
admin = null; // Now it's unreachable → collected
💍 Example 3: Interlinked Objects
function marry(man, woman) {
man.wife = woman;
woman.husband = man;
return { father: man, mother: woman };
}
let family = marry({ name: "John" }, { name: "Ann" });
delete family.father;
delete family.mother.husband;
// John now has no incoming reference → garbage
🗂️ Diagram — Mark-and-Sweep (Simplified)
Roots
|
Global → Object A → Object B → Object C
If Object A is unlinked:
Object B, C become unreachable
GC sweeps and deletes them
🔹 2. Fill Any Gaps (Advanced Concepts, Edge Cases)
🔍 What Devs Often Miss:
Outgoing references don’t keep an object alive — Only incoming ones matter.
Closures: A function can retain variables even after it returns. These remain in memory if still referenced.
function outer() { let secret = "💥"; return function inner() { console.log(secret); }; } const fn = outer(); // `secret` is still reachable!
Memory Leaks Still Happen:
Forgotten timers (
setInterval
)Detached DOM nodes still referenced
Closures capturing heavy objects
⚙️ GC Algorithms (Behind the Scenes)
Algorithm | What It Does |
Mark-and-Sweep | Marks reachable objects → deletes others |
Generational GC | Separates short-lived and long-lived objects |
Incremental GC | Splits work into chunks to avoid pauses |
Idle-Time GC | Runs GC only when the main thread is idle |
🧠 Engines like V8 use a hybrid of these for speed.
🔹 3. Challenge Me Deeply
🟢 Basic
Create an object and assign it to two variables. Null one and observe memory.
Create an object that has a reference to itself. Explain if it's garbage.
Build a function returning a closure that captures a variable. Will GC collect it?
🟡 Intermediate
Create a circular structure with three objects. Write logic to break the cycle.
Create a timer (
setInterval
) that logs a value. Make it garbage-safe.Store DOM elements in an array. Then remove from DOM. Will memory be freed?
Simulate a memory leak by attaching a closure to a button’s event listener.
🔴 Advanced
Create a deep closure chain. Identify when each layer becomes GC-eligible.
Track retained memory in Chrome DevTools using heap snapshots.
Build a custom “reference tracker” that shows whether an object is still reachable.
🎯 Bonus Brain Twister:
- How can an object with no variables pointing to it still stay in memory?
🔹 4. Interview-Ready Questions
🧠 Conceptual
What does “reachability” mean in JavaScript memory management?
Describe the lifecycle of an object in memory.
Why is a circular reference not a problem in modern GC?
🔎 Debugging Scenario
function createUser() {
let secret = "123";
return () => console.log(secret);
}
const userFn = createUser();
// Question: Is `secret` still in memory? Why?
✅ Best Practices
✅ Do | ❌ Don’t |
Clean up timers & intervals | Leave setInterval running indefinitely |
Null out DOM refs on removal | Hold references to removed elements |
Detach event listeners | Forget closures attached to DOM |
🔹 5. Real-World Usage
Front-End:
React: Memory leaks from uncleaned effects or stale closures
DOM: Holding references to removed nodes causes leaks
Back-End (Node.js):
Holding large objects in global space (e.g., big cache)
Unhandled listeners (e.g.,
EventEmitter
leaks)
Libraries:
React hooks (e.g.,
useEffect
cleanup)RxJS subscriptions (
.unsubscribe()
to avoid leaks)EventEmitter: Unremoved listeners pile up memory
🔹 6. Remember Like a Pro
🧠 Mnemonic: "RRR" = Reach → Reference → Retain
Only Reachable values stay alive
References don’t equal retention — must come from a root
Unreferenced → Unreachable → Removed
📌 Cheatsheet:
Concept | Retained? | Why? |
Referenced by closure | ✅ | Active stack |
Referenced by timer | ✅ | Timer root |
Circular references | ❌ | GC handles them |
DOM node removed but still in JS var | ✅ | Still reachable |
🔹 7. Apply It in a Fun Way
🧪 Mini Project: Memory Leak Detector Utility
Create a tool that:
Tracks object creation
Lets you “unlink” references
Flags uncollected memory (simulated)
Steps:
Create
trackObject(obj)
that stores it in a WeakMapSimulate reference breaking via
obj = null
Show if it’s still in memory (mocked)
Tie to a UI showing “Retained” or “Freed”
🔁 Extend it to:
Warn if timers or DOM leaks are likely
Show dependency graphs like Chrome DevTools
➕ Bonus: Expert Corner
🔥 Used in Open Source:
React, Vue, Angular: Handle GC traps around lifecycle
Node.js: GC tuning via
--max-old-space-size
Chrome DevTools: Built-in GC profiler
⚠️ Common Mistakes:
Forgetting
.removeEventListener
Not cleaning up RxJS subscriptions
Using globals for caching without purging
⚡ Performance Tip:
Avoid holding large objects longer than necessary. Split tasks using setTimeout(..., 0)
to let GC run.
Subscribe to my newsletter
Read articles from manoj ymk directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by
