How I tracked down a 36GB memory leak in a Claude Code memory server A developer tracked down a 36GB memory leak in a Claude Code memory server caused by sql.js WebAssembly filesystem (MEMFS) not being cleaned up. The leak occurred because garbage-collecting the JavaScript Database wrapper did not free the MEMFS file created inside the WASM module, leaving 11MB database images per open operation. The fix involved adding an RSS watchdog to the proxy to restart the child process when memory crosses a threshold. A debugging story about heap snapshots, native memory that --max-old-space-size can't touch, and a WebAssembly filesystem quietly hoarding files. I run a small service that gives a team of Claude Code users one shared memory store. Mechanically it's a Node/Express proxy that wraps a stdio MCP server ruflo and exposes it over HTTP. You don't need the product to follow the bug — just one fact: a long-lived Node process serves memory operations, and underneath it uses sql.js SQLite compiled to WebAssembly to hold the store. One instance in production kept growing. Not spiking — creeping . ~36 GB RSS over six weeks, then the cgroup OOM-killer would reap it and the clock reset. Classic leak shape. The proxy and the wrapped MCP child are separate processes. ps settled it fast: the proxy sat flat at ~60 MB; the ruflo mcp start child was the one ballooning. So the leak was below my code, in the wrapped process. Good — narrower problem. First instinct on a Node leak is the V8 heap. So I looked at process.memoryUsage on the live child: rss 1385 MB heapTotal 24 MB heapUsed 21 MB external 1286 MB arrayBuffers 995 MB This is the whole story in five numbers. heapTotal — the V8 JS heap — is flat at 24 MB. The growth is entirely in external / arrayBuffers : native memory backing ArrayBuffer s, That immediately kills two "obvious" fixes: --max-old-space-size So: what holds ~1 GB of ArrayBuffer s? I opened the inspector on the live process kill -USR1