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;}