HomeBytesheetsRoadmapsUI TemplatesUI ToolsStack Discussion
3 Topics
Chapter•105 Minutes

Performance, Memory, and Profiling

Diagnose slow Node.js applications, understand memory usage, identify event-loop blocking, optimize database access, and use profiling tools.

Avoiding Event-Loop Blocking

Node.js performance depends heavily on keeping the event loop responsive. Expensive synchronous operations, huge JSON parsing or serialization, inefficient regular expressions, and CPU-heavy algorithms can delay unrelated requests.

Performance optimization should begin with measurement rather than assumptions.

Avoid CPU-Heavy Work in Request Handlers
app.get('/report', async (req, res) => {
  const report = await generateReportInWorker(req.query.id);
  res.json(report);
});
💡 CPU-intensive report generation can be moved to a worker or background job so the HTTP event loop remains responsive.
Key Takeaways
  • Keep request handlers lightweight when possible.
  • Move expensive CPU work to workers or background processes.
  • Measure event-loop latency to detect blocking workloads.
Knowledge Check

What is a common cause of poor Node.js concurrency?

Memory Management and Garbage Collection

Node.js uses V8's garbage collector to reclaim memory that is no longer reachable. Memory leaks occur when application references unintentionally keep objects alive.

Common causes include unbounded caches, global collections, event listeners that are never removed, timers that remain active, and closures retaining large objects.

Memory Leaks Are Reachability Problems

Garbage collection cannot reclaim objects that are still reachable. Look for references that live longer than the data they retain.

Avoiding an Unbounded Cache
const cache = new Map();

function setUser(id, user) {
  cache.set(id, user);
}

// Production code should define an eviction or expiration strategy.
💡 A plain Map grows indefinitely unless the application explicitly removes entries. Production caches should have bounded size or expiration.
Key Takeaways
  • Garbage collection removes unreachable objects.
  • Unbounded collections are a common source of memory growth.
  • Heap snapshots can help identify retained objects.
Knowledge Check

Why can an unbounded Map cause memory growth?

Profiling and Performance Optimization

Node.js applications can be profiled using tools such as the Node inspector, CPU profiles, heap snapshots, and performance APIs. Production performance work should examine real bottlenecks such as database queries, network calls, serialization, event-loop delay, and memory pressure.

Useful optimizations include database indexing, batching, pagination, connection pooling, caching, stream processing, and algorithmic improvements.

Key Takeaways
  • Profile before optimizing.
  • Database and network latency are often more significant than JavaScript micro-optimizations.
  • Measure latency distributions such as p50, p95, and p99 rather than only averages.
Knowledge Check

What is usually the best first step before a performance optimization?