Files
cline/scripts
Mikołaj Kondratek 70f0e8d548 feat(memory-observability): add periodic memory logging to cline-core (#10343)
* feat(memory-observability): add periodic memory logging to cline-core

Introduces a lightweight memory monitor that logs process.memoryUsage()
snapshots to the existing cline-core log every 5 minutes, plus an
immediate baseline at startup and a final snapshot at graceful shutdown.

Each entry is written as a single `[MEMORY] key=valueMB ...` line so it
is trivially greppable and parseable:

    grep '\[MEMORY\]' ~/.cline/cline-core-service.log

The timer is unref()'d so it does not keep the event loop alive on its
own, ensuring the Node process can still exit cleanly.

Also adds an informational log line after process.chdir(__dirname) that
records where V8 will write heap snapshots if --heapsnapshot-near-heap-limit
triggers them, and a best-effort process.on("exit") handler that scans
cwd for .heapsnapshot files on abnormal exit and logs their paths/sizes
so post-mortem investigation starts with the diagnostic data in hand.

This is Part 1 (periodic memory logging) and the Node-side portions of
Part 2 (snapshot directory + exit handler) of the memory observability
implementation plan. The V8 flag itself and the
~/.cline/heapsnapshots/ move-and-cap cleanup live in the Kotlin
CoreProcessManager and are applied separately in the plugin repo.

No business-logic changes; purely additive diagnostics.

* chore(memory-observability): enable --heapsnapshot-near-heap-limit=3 in runclinecore.sh

When cline-core approaches the V8 heap ceiling, V8 will now write up to
3 .heapsnapshot files to the current working directory before giving up
and crashing. These snapshots can be loaded into Chrome DevTools → Memory
tab to identify the objects retaining the most memory.

N=3 is chosen because the last snapshot (written just before the fatal
OOM) shows only live, truly-unreclaimable objects — the earlier ones still
contain garbage the GC hadn't collected yet. Having all three lets us
compare.

This flag is a V8 runtime flag and must be passed on the node command
line; it cannot be enabled from JavaScript at runtime.

Matches the equivalent change on the cline-core launcher in the IntelliJ
plugin repo (CoreProcessManager.kt).

* chore(memory-observability): reduce --heapsnapshot-near-heap-limit from 3 to 1

Reviewer concern: with --max-old-space-size=8192, each heap snapshot
serializes at roughly 4-5x heapUsed on disk, so three snapshots can
burst 24-40 GB to disk in the seconds before an OOM crash — right
when the system is already under memory/CPU pressure. On a laptop
with <40 GB free this can leave partial/corrupted snapshots or
trigger OS pressure on unrelated processes.

The plan doc originally argued 'snapshot 3 of 3 is most valuable
because it contains only live objects'. In practice, by the time V8
triggers the flag it has already run aggressive mark-compact cycles,
so snapshot 1 is nearly-all-live too. Our own Scenario B verification
run confirmed that even the first snapshot contained the retainer
chain — snapshots 2 and 3 added no diagnostic signal.

Trade-off:
  - per-OOM disk burst:      24-40 GB  ->  8-14 GB  (3x reduction)
  - time-to-crash (frozen):  30-60 s   ->  10-20 s  (3x reduction)
  - diagnostic signal:       essentially unchanged

The persistent-directory cap in CoreProcessManager.kt stays at 3, so
we still retain snapshots from the 3 most recent OOM events for
cross-event comparison.

* chore(memory-observability): shorten runclinecore.sh flag comments

The one-line pointer to CoreProcessManager.kt was more noise than
signal given the flags are visible on the same line as the command.
Rationale for the --heapsnapshot-near-heap-limit value lives in the
Kotlin constant's KDoc and in the commit log.
2026-04-23 13:34:51 +09:00
..
2025-10-10 20:55:35 -07:00