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

Status Closed — not planned
Reported on v2.1.74
Maintainer reply None cached
Activity 3 comments · opened Mar 12, 2026 · 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 ↗