Your Express.js application's memory usage grows steadily over time. Starting at 150 MB after deployment, it reaches 1.2 GB within 6 hours and eventually gets OOM-killed by the container orchestrator. Restarting the process temporarily fixes the issue, but memory climbs again.
The application has several middleware layers and handles around 1,000 requests per minute. Memory profiling shows that the heap grows by approximately 2 MB every minute, but garbage collection runs regularly and reclaims some memory. The leak is gradual, making it hard to pinpoint.
You have narrowed the issue to the following suspicious patterns in the codebase:
Pattern 1: Request Logger Middleware
const requestLogs: any[] = [];
app.use((req, res, next) => {
requestLogs.push({
method: req.method,
url: req.url,
timestamp: Date.now(),
headers: req.headers,
});
next();
});
Pattern 2: Cache Without Bounds
const cache = new Map();
function getCachedUser(id: string) {
if (!cache.has(id)) {
const user = db.getUserById(id);
cache.set(id, user);
}
return cache.get(id);
}
Pattern 3: Event Listener Accumulation
app.use((req, res, next) => {
const onData = (chunk: Buffer) => {
// process chunk with access to req via closure
processChunk(chunk, req);
};
someEventEmitter.on('data', onData);
next();
// Listener is never removed
});