Residual native memory leak in v2.1.74 despite streaming buffer fix

Resolved 💬 3 comments Opened Mar 12, 2026 by NickBevers Closed Mar 12, 2026

Summary

After upgrading from v2.1.72 to v2.1.74, the streaming buffer leak fix (noted in the changelog) reduced the memory growth rate by ~12x, but a residual native memory leak persists. RSS reaches ~548 MB within 5 minutes of uptime, with ~348 MB unaccounted for outside the JS heap.

Environment

  • Claude Code version: 2.1.74 (native binary install)
  • Platform: macOS (Darwin 24.6.0)
  • Node.js (bundled): v24.3.0
  • Architecture: arm64

Diagnostics

Dump 1 — v2.1.72 (39 seconds uptime)

{
  "uptimeSeconds": 39.37,
  "memoryUsage": {
    "heapUsed": 98852747,
    "heapTotal": 41785344,
    "external": 64821444,
    "arrayBuffers": 18200731,
    "rss": 872808448
  },
  "memoryGrowthRate": {
    "bytesPerSecond": 22167410,
    "mbPerHour": 76105.76
  },
  "v8HeapStats": {
    "heapSizeLimit": 8728576000,
    "mallocedMemory": 99115156,
    "peakMallocedMemory": 872857600
  },
  "activeHandles": 0,
  "activeRequests": 0
}

Dump 2 — v2.1.74 (297 seconds uptime)

{
  "uptimeSeconds": 296.51,
  "memoryUsage": {
    "heapUsed": 150712949,
    "heapTotal": 57100288,
    "external": 109707893,
    "arrayBuffers": 38341295,
    "rss": 548061184
  },
  "memoryGrowthRate": {
    "bytesPerSecond": 1848395,
    "mbPerHour": 6345.96
  },
  "v8HeapStats": {
    "heapSizeLimit": 5480939520,
    "mallocedMemory": 150975205,
    "peakMallocedMemory": 548093952
  },
  "activeHandles": 0,
  "activeRequests": 0
}

Comparison

| Metric | v2.1.72 (39s) | v2.1.74 (297s) |
|---|---|---|
| RSS | 873 MB | 548 MB |
| Heap Used | 99 MB | 151 MB |
| External | 65 MB | 110 MB |
| Growth Rate | 76,106 MB/hr | 6,346 MB/hr |

Heap Snapshot Analysis (v2.1.74)

Parsed the V8 heap snapshot (~36 MB). Key findings:

Top allocations by self-size

| Size (MB) | Count | Type | Name |
|---|---|---|---|
| 32.53 | 9 | object | ArrayBuffer |
| 9.79 | 7 | native | Blob |
| 8.93 | 3,223 | code | FunctionCodeBlock |
| 7.32 | 11,532 | code | UnlinkedFunctionCodeBlock |
| 3.80 | 124,446 | closure | Function |

Two 16 MB ArrayBuffers — yoga-layout WASM

Both are retained by WebAssembly.Memory via a JSLexicalEnvironment with embind bindings (toWireType, getInheritedInstanceCount, get_first_emval). Source path:

yoga-layout/dist/binaries/yoga-wasm-base64-esm.js

This is the yoga-layout WASM module (used by Ink for terminal UI layout). 32 MB fixed cost — not a leak, but a significant baseline allocation that could be optimized (e.g., lazy-load or reduce initial memory).

Six Blobs (9.8 MB) — Bun.embeddedFiles

Retained by GlobalObject → Bun → embeddedFiles. Static assets baked into the binary. Not a leak.

Native memory gap

  • JS heap self-size: ~90 MB
  • External/ArrayBuffers: ~110 MB
  • RSS: 548 MB
  • Unaccounted native memory: ~348 MB

This gap points to native addon memory not tracked by V8. tree-sitter is reported as unavailable in debug logs, so the prime suspect is node-pty or the Bun runtime's internal allocations.

heapUsed > heapTotal anomaly

Both dumps show heapUsed exceeding heapTotal (e.g., 151 MB vs 57 MB). This appears to be a reporting issue — possibly a snapshot timing artifact or a unit mismatch in the diagnostics collection code.

maxRSS reporting bug

resourceUsage.maxRSS reports values in the hundreds of billions (e.g., 561248206848 ≈ 523 GB), which is impossible. On macOS, uv_getrusage returns maxRSS in bytes, but process.resourceUsage() is expected to return KB. This looks like a unit conversion bug in the diagnostics reporter.

Steps to Reproduce

  1. Launch Claude Code v2.1.74 (native binary on macOS)
  2. Run /heapdump after ~5 minutes of normal interactive use
  3. Observe RSS significantly exceeding JS heap + external memory

Expected Behavior

RSS should stabilize and remain proportional to JS heap + external memory, without unbounded native memory growth.

Additional Notes

  • The v2.1.74 changelog fix ("streaming API response buffers not released when generator terminated early") clearly helped — growth rate dropped from ~76 GB/hr to ~6.3 GB/hr
  • MCP server reconnection failures (SSE timeouts, WebSocket disconnects) were observed in debug logs and may contribute to native memory not being freed
  • Broken symlink logged repeatedly: /Library/Application Support/ClaudeCode/managed-settings.json (minor, but noisy)

View original on GitHub ↗

This issue has 3 comments on GitHub. Read the full discussion on GitHub ↗