← Back to list

How I Fixed a Memory Leak in My Node.js App (And Finally Understood V8’s Garbage Collection)

A pizza analogy, 3 code examples, and why your JavaScript objects don’t just ‘disappear’

Ahmedrao · 2025-05-30 13:24 · 8 claps · 2.8 min read
#javascript #javascript-v8-engine #nodejs #web-performance #memory-leak
Open on Medium ↗
Wiki topics: 🌐 · Web Development

My Node.js Server Kept Crashing Every 72 Hours.

“Just restart it,” said my team. But I couldn’t let it go. Every time our server went down, we lost orders — real money. So I dove into the logs.

What I found was terrifying: V8 was hoarding objects like a digital packrat.

If you think JavaScript magically “cleans up” memory, this article is for you. Let’s break down how V8’s Garbage Collector (GC) really works — and how you might be making memory leaks without even knowing it.

🍕 The Pizza Shop Analogy

Imagine your Node.js app is a pizza shop.

  • The kitchen fridge = V8’s memory heap (limited space!)
  • The ingredients = your JavaScript variables and objects
  • The cleanup crew = V8’s Garbage Collector

Here’s the problem: If you leave old toppings (objects) in the fridge (memory), the fridge fills up. At some point, the kitchen crashes — the server can’t handle it anymore.

🔥 3 Memory Crimes You’re Probably Committing

1️⃣ The Accidental Global

Ever done this?

function cook() {
  leak = "oops"; // no 'var', 'let', or 'const' = accidental global
}
cook();

Now leak lives forever in the global scope. V8’s GC won’t touch it—it’s still “needed”!

2️⃣ The Closure Clutter

Closures are powerful, but they hold onto their variables — sometimes too long.

function pizzaMaker() {
  const secretIngredient = "truffle oil";
  return function makePizza() {
    console.log(`Using ${secretIngredient}`);
  };
}

const chef = pizzaMaker();
// 'secretIngredient' stays in memory as long as 'chef' exists

If you keep chef around (say, in a cache), that entire scope sticks in memory.

3️⃣ The Forgotten Timer

Timers are sneaky.

const customer = { name: "Alice" };

setInterval(() => {
  console.log(`Hello, ${customer.name}`);
}, 1000);

Even if you delete customer, that interval still holds a reference → memory leak!

🧹 V8’s Secret Cleanup Routine

Generational Collection: The Pizza Dough Rule

  • New objects (like fresh pizza dough) → checked often (cheap to throw away).
  • Old objects (like cured pepperoni) → checked less often (assumed valuable).

This is called the generational hypothesis:

Most objects die young.

Mark-and-Sweep: The Expired Anchovies Rule

When GC runs, it marks reachable objects (like fresh cheese) and sweeps away unreferenced ones (like week-old anchovies).

let a = {};
let b = a; // reachable
a = null;  // b still points to the object → not collected

Orinoco: The No-Freeze GC

Older versions of V8 would pause your app to clean memory. Orinoco (V8’s modern GC) runs concurrently, so your app keeps running while the cleanup happens.

But:

  • If you’re holding onto a lot of memory → GC slows down, and you still risk crashing.

🍕 Interactive Demo: Memory Leak Pizza Party

Try this in Node.js:

// Run this in Node.js and watch memory!
let pizzaToppings = [];

setInterval(() => {
  pizzaToppings.push(new Array(1000).fill("pepperoni"));
  console.log(`Toppings in memory: ${pizzaToppings.length}`);
}, 100);

Now open your Task Manager or htop—watch the memory climb! 📝 Comment out the push() line → the leak stops. That’s V8’s GC in action: if you stop holding onto objects, GC can clean them up.

🧠 Pro Tips for Memory Hygiene

Set Node’s Memory Limit Add --max-old-space-size=2048 to your Node.js command to limit memory usage.

Use Chrome DevTools for Memory Profiling Run Node.js with --inspect → open chrome://inspectMemory tabHeap snapshots. Find your leaks like a detective.

WeakMap is Your Friend For caches, use WeakMap—it doesn’t prevent GC when objects are no longer used.

const cache = new WeakMap();
let obj = {};
cache.set(obj, "cached value");
obj = null; // No memory leak!

⚖️ Ethical Consideration: Optimize, But Don’t Obsess

When I optimized our app’s memory, our AWS bill dropped by 30%. That’s real money. But — don’t go overboard.

Sometimes, “good enough” GC is better than endless manual cleanup. Focus on leaks that actually cause problems.

🗣️ Your Turn: Try the Pizza Experiment!

Run the demo above — share your memory graphs in the comments! What’s the weirdest memory leak you’ve encountered? Let’s swap war stories. 🍕💻

#JavaScript #V8Engine #NodeJS #WebPerformance #MemoryLeak #Programming


메타데이터
post_id
dd5665ea83af
slug
how-i-fixed-a-memory-leak-in-my-node-js-app-and-finally-understood-v8s-garbage-collection-dd5665ea83af
url
https://medium.com/@ahmedrao609/how-i-fixed-a-memory-leak-in-my-node-js-app-and-finally-understood-v8s-garbage-collection-dd5665ea83af
canonical_url
https://medium.com/@ahmedrao609/how-i-fixed-a-memory-leak-in-my-node-js-app-and-finally-understood-v8s-garbage-collection-dd5665ea83af
author_url
https://medium.com/@ahmedrao609
status
ok
fetched_at
2026-08-26 11:17:57