JavaScript Notes
Master JavaScript memory management: stack vs heap, allocation lifecycle, memory leaks, WeakMap, garbage collection, and interview Q&A with diagrams.
What is Memory Management?
Memory management refers to how JavaScript allocates memory when you create values and how it frees that memory when values are no longer needed. JavaScript handles this automatically, but understanding the process helps you write efficient, leak-free code.
One-liner: Memory management is how JavaScript decides where to store your data (allocation) and when to delete it (deallocation via GC).
The Two Memory Stores
JavaScript uses two memory areas:
Memory Lifecycle Diagram
Stack Memory — Primitives
function calculate() {
let a = 10; // Stored on STACK
let b = 20; // Stored on STACK
let sum = a + b; // Computed, stored on STACK
return sum;
}
const result = calculate();
console.log(result);
// After calculate() returns: a, b, sum are all popped from stack30
Primitive values are stored by value on the stack. When a function returns, its stack frame is automatically cleaned.
Heap Memory — Objects and References
const person = { name: "Ananya", age: 25 }; // Object on HEAP
const alias = person; // alias holds the SAME reference
alias.age = 30; // Modifies the SAME heap object
console.log(person.age); // 30 — same reference!
console.log(alias === person); // true — same memory address30 true
Shallow Copy vs Deep Copy
// SHALLOW COPY — copies only top-level properties
const original = { name: "Raj", address: { city: "Delhi" } };
const shallow = { ...original };
shallow.address.city = "Mumbai"; // Modifies SHARED nested object!
console.log(original.address.city); // "Mumbai" — affected!Mumbai
// DEEP COPY — creates completely independent copy
const deep = JSON.parse(JSON.stringify(original));
deep.address.city = "Bengaluru";
console.log(original.address.city); // "Mumbai" — unchanged!Mumbai
Memory Allocation for Different Types
// Primitive — value copy
let num1 = 100;
let num2 = num1; // Copy of value
num2 = 200;
console.log(num1); // 100 — unaffected
console.log(num2); // 200100 200
// Object — reference copy
let obj1 = { val: 100 };
let obj2 = obj1; // Copy of REFERENCE
obj2.val = 200;
console.log(obj1.val); // 200 — AFFECTED!
console.log(obj2.val); // 200200 200
Memory Leaks — Identification and Prevention
Leak Type 1 — Accidental Global Variables
// BAD — creates global variable
function setup() {
config = { debug: true }; // No let/const/var → global!
}
setup();
// `config` persists forever in global scope// GOOD
function setup() {
const config = { debug: true }; // Block scoped
}Leak Type 2 — Closures Capturing Large Data
// POTENTIAL LEAK — bigData stays alive as long as callback is alive
function processLargeFile(data) {
const bigData = new ArrayBuffer(50 * 1024 * 1024); // 50MB
document.getElementById("btn").addEventListener("click", function() {
// bigData is captured in closure — never freed while btn exists
console.log(data.name);
});
}Leak Type 3 — setInterval Not Cleared
Leak Type 4 — Detached DOM Nodes
let detachedNode;
function createAndRemove() {
const div = document.createElement("div");
document.body.appendChild(div);
detachedNode = div; // JS still holds reference
document.body.removeChild(div); // Removed from DOM
// But detachedNode → div → can't be GC'd!
}
// Fix: null the reference when done
detachedNode = null;WeakMap and WeakSet for Memory-Efficient Caching
When you want to associate data with objects without preventing GC:
const cache = new WeakMap(); // Keys are objects, held weakly
function computeExpensiveResult(obj) {
if (cache.has(obj)) {
return cache.get(obj); // Return cached result
}
const result = obj.value * obj.multiplier; // Expensive computation
cache.set(obj, result); // Cache with weak reference
return result;
}
let data = { value: 100, multiplier: 3 };
console.log(computeExpensiveResult(data)); // 300
console.log(computeExpensiveResult(data)); // 300 (from cache)
data = null; // Original object can now be GC'd — WeakMap entry removed!300 300
With a regular Map, the cache would hold data alive even after data = null. WeakMap doesn't.
Memory Profiling — What to Look For
Common Mistakes
❌ Mistake 1 — Thinking Objects Are Passed by Value
function update(obj) {
obj.name = "Updated"; // Modifies the ORIGINAL
}
const user = { name: "Original" };
update(user);
console.log(user.name);Updated
Objects are passed by reference (the reference is copied, not the object). Modifying through the reference affects the original.
❌ Mistake 2 — Thinking null Frees Memory Immediately
let bigArray = new Array(1000000).fill("data");
bigArray = null; // Makes it ELIGIBLE for GC — doesn't free immediatelySetting to null removes the reference, making the object eligible for collection. The GC decides when to actually free it.
Interview Questions 🎯
Q1. What is the difference between stack and heap memory in JavaScript?
- Stack: Stores primitive values directly, function call frames. Fast, LIFO, automatically managed when functions return.
- Heap: Stores objects, arrays, functions. Dynamic size. Memory freed by garbage collector when no references exist.
Q2. What is the memory lifecycle in JavaScript?
- Allocation: Memory reserved when value created
- Use: Read/write through variables/references
- Deallocation: GC frees memory when value is unreachable (no remaining references)
Q3. How are objects and primitives stored differently?
- Primitives (number, string, boolean, null, undefined, symbol): stored by value on the stack
- Objects (objects, arrays, functions): stored on the heap; variables hold a reference (address) to the heap location
Q4. What is a memory leak in JavaScript?
A memory leak occurs when memory that should be freed (object no longer needed) cannot be freed because unintentional references keep it reachable. Common causes: accidental globals, forgotten event listeners/timers, closures capturing large data, detached DOM nodes.
Q5. How do WeakMap and WeakSet help with memory management?
They hold weak references to their keys/values — these references don't prevent garbage collection. When the referenced object has no other strong references, it's collected and the WeakMap/WeakSet entry is automatically removed. Ideal for caches, metadata, and associations where objects have their own lifetimes.
Q6. What is the difference between shallow copy and deep copy in memory?
- Shallow copy (
{...obj},Object.assign()): copies only top-level properties. Nested objects are still shared references — modifying nested data affects both copies. - Deep copy (
JSON.parse(JSON.stringify()),structuredClone()): creates completely independent copies of all nested objects.
Q7. Why do closures sometimes cause memory leaks?
A closure keeps a reference to the outer function's variables. If the closure is long-lived (stored globally, in event handlers, setInterval), it prevents those variables from being garbage collected — even large objects that are no longer actively used.
Q8. How can you detect a memory leak in a JavaScript application?
Use Chrome DevTools Memory tab: take heap snapshots before and after performing an action, then compare. Look for objects that keep increasing count without decreasing. Also use the Timeline recording to see if memory steadily increases without dropping after GC.
Key Takeaways 🔑
- Stack: primitive values, fast, auto-cleaned on function return
- Heap: objects/arrays/functions, dynamic, cleaned by garbage collector
- Variables holding objects contain references (pointers) — not the object itself
- Memory lifecycle: Allocate → Use → Garbage Collection (automatic)
- Common memory leaks: accidental globals, leaked event listeners, closures over large data, detached DOM
WeakMap/WeakSetallow GC-friendly associations — keys held weakly- Setting
nullmakes an object eligible for GC — doesn't free immediately - Profile memory in Chrome DevTools to detect growing heap snapshots
Summary
JavaScript memory management works automatically through garbage collection, but understanding it is essential for writing efficient applications. Memory is split into the stack (primitives, fast, auto-cleaned) and the heap (objects, arrays, functions — managed by GC). The three phases — allocation, use, and deallocation — happen automatically, but you can accidentally prevent deallocation through memory leaks. The key defensive techniques are: always use let/const, clean up event listeners and intervals, null out references when done, and use WeakMap/WeakSet for GC-friendly associations. Profiling with Chrome DevTools' Memory tab helps identify and fix leaks in production applications.
Exam Focus
Revise definitions, diagrams, examples, and short-answer points for JavaScript Memory Management - Complete Guide with Lifecycle Diagrams.
Interview Use
Prepare one clear explanation, one practical example, and one common mistake for this JavaScript Master Course topic.
Search Terms
javascript-complete-guide, javascript master course, javascript, complete, guide, advanced, memory, management
Related JavaScript Master Course Topics