Managing Memory
1. Understanding Memory Challenges
| Source | Per-Conn Footprint |
|---|---|
| JS object | ~2-10 KB |
| TCP buffers | ~64-256 KB (kernel) |
| permessage-deflate state | ~256 KB / direction |
| App context | Variable (subs, queues) |
Note: 10k connections × 512 KB ≈ 5 GB. Disable per-conn compression context or stream-only if memory is bound.
2. Preventing Memory Leaks
| Cause | Fix |
|---|---|
| Forgotten listeners | AbortController |
| Closures over ws | Null out on close |
| Unbounded queues | Cap size |
| Maps keyed by ws | Use WeakMap |
| Pending Promises | Reject on close |
3. Using Weak References
Example: WeakMap context
const ctxs = new WeakMap();
ctxs.set(ws, { subs: new Set(), userId });
// no manual cleanup when ws is GC'd
| API | Use |
|---|---|
WeakMap | Object-key map, auto-evict |
WeakSet | Set of objects, auto-evict |
WeakRef | Hold without preventing GC |
FinalizationRegistry | Post-GC cleanup hook |
4. Implementing Connection Cleanup
Example: Centralized teardown
function cleanup(ws) {
ws.removeAllListeners?.();
clearTimeout(ws.authTimer);
clearInterval(ws.hbTimer);
for (const [id, p] of ws.pending) p.reject(new Error("closed"));
ws.pending.clear();
}
5. Monitoring Memory Usage
| Tool | Use |
|---|---|
process.memoryUsage() | Node RSS/heap |
--inspect + Chrome | Heap snapshots |
clinic.js heapprofile | Allocation profiling |
performance.memory | Browser (Chromium) |
6. Limiting Buffer Sizes
| Bound | Where |
|---|---|
maxPayload | ws server option |
| App outbox cap | Drop / reject |
| Subscription cap | Per connection |
| Pending RPCs cap | Avoid runaway maps |
7. Implementing Message Expiration
Example: TTL on queued message
function enqueue(msg, ttlMs = 5000) {
outbox.push({ msg, deadline: Date.now() + ttlMs });
}
function flush() {
const now = Date.now();
for (const it of outbox) if (it.deadline > now) ws.send(it.msg);
outbox.length = 0;
}
8. Garbage Collection Considerations
| Practice | Detail |
|---|---|
| Avoid huge buffers in closures | Null after use |
| Avoid string + binary churn | Reuse Uint8Array pools |
| Tune V8 heap | --max-old-space-size |
9. Profiling Memory
| Step | Action |
|---|---|
| 1 | Take baseline heap snapshot |
| 2 | Run scenario (open/close N conns) |
| 3 | Take second snapshot |
| 4 | Diff retained sizes |
| 5 | Track retainer paths → root cause |
10. Handling Out of Memory
| Mitigation | Detail |
|---|---|
| Process exit + restart | Fast recovery (PM2/systemd) |
| Soft cap | Reject new conns at 80% memory |
| Shed load | Close idle subscribers |
| Health endpoint | Reports degraded → LB drains |