java_gc_snapshot
Capture GC snapshot data from a Java process by PID, measuring pause frequency and heap usage over time to diagnose memory pressure.
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| pid | Yes | ||
| interval_s | No | ||
| samples | No |
Output Schema
| Name | Required | Description | Default |
|---|---|---|---|
No arguments | |||
Implementation Reference
- src/heap_seance_mcp/tools.py:88-124 (handler)Core handler for java_gc_snapshot: runs 'jstat -gcutil' via shell_tools, parses output with parse_jstat_gcutil, computes GC pressure heuristics (OldGen utilization, FullGC delta, oldgen slope), and returns an ok_result with evidence/metrics.
def java_gc_snapshot(pid: int, interval_s: int = 2, samples: int = 6) -> dict[str, Any]: try: require_binary("jstat", "Install OpenJDK 17+ so jstat is available.") interval_ms = max(1, interval_s) * 1000 output = ensure_success( run_command(["jstat", "-gcutil", str(pid), f"{interval_ms}ms", str(max(2, samples))]) ).stdout parsed = parse_jstat_gcutil(output) except Exception as exc: # noqa: BLE001 return _command_failed(exc) summary = parsed["summary"] max_oldgen = float(summary["max_oldgen_utilization"]) full_gc_delta = float(summary["full_gc_delta"]) oldgen_slope = float(summary["oldgen_slope"]) evidence = [ f"Collected {summary['sample_count']} gcutil samples for PID {pid}.", f"OldGen max={max_oldgen:.2f}% slope={oldgen_slope:.2f} FullGC delta={full_gc_delta:.0f}.", ] pressure = max_oldgen >= 80.0 and full_gc_delta >= 1.0 and oldgen_slope > 0.0 confidence = "medium" if pressure else "low" return ok_result( evidence=evidence, metrics={ "pid": pid, "series": parsed["series"], "summary": summary, "pressure_detected": pressure, }, confidence=confidence, next_recommended_action=( "Correlate with 3 histogram samples and escalate to deep forensics if pressure persists." ), ) - src/heap_seance_mcp/server.py:31-33 (registration)MCP tool registration: decorates java_gc_snapshot as an MCP tool via @mcp.tool(), forwarding PID/interval_s/samples parameters to tools.java_gc_snapshot.
@mcp.tool() def java_gc_snapshot(pid: int, interval_s: int = 2, samples: int = 6) -> dict[str, Any]: return tools.java_gc_snapshot(pid=pid, interval_s=interval_s, samples=samples) - src/heap_seance_mcp/parsers.py:31-69 (schema)Parser helper parse_jstat_gcutil: parses jstat -gcutil output into samples, oldgen utilization series, full GC count series, and summary statistics (max_oldgen_utilization, oldgen_slope, full_gc_delta).
def parse_jstat_gcutil(text: str) -> dict[str, Any]: lines = [line.strip() for line in text.splitlines() if line.strip()] if len(lines) < 2: raise ValueError("Expected jstat output with header and at least one sample line") header = lines[0].split() samples: list[dict[str, float]] = [] for line in lines[1:]: parts = line.split() if len(parts) != len(header): continue row: dict[str, float] = {} for key, value in zip(header, parts): row[key] = float(value.replace(",", ".")) samples.append(row) if not samples: raise ValueError("No parseable jstat samples found") oldgen_series = [sample.get("O", 0.0) for sample in samples] full_gc_series = [sample.get("FGC", 0.0) for sample in samples] oldgen_slope = oldgen_series[-1] - oldgen_series[0] return { "header": header, "samples": samples, "series": { "oldgen_utilization": oldgen_series, "full_gc_count": full_gc_series, }, "summary": { "sample_count": len(samples), "max_oldgen_utilization": max(oldgen_series), "oldgen_slope": oldgen_slope, "full_gc_delta": full_gc_series[-1] - full_gc_series[0], }, } - src/heap_seance_mcp/results.py:37-54 (helper)Helper ok_result: constructs a standard 'ok' ToolResult dict used by java_gc_snapshot to return status, evidence, metrics, confidence, and next_recommended_action.
def ok_result( *, evidence: list[str] | None = None, metrics: dict[str, Any] | None = None, confidence: str = "low", next_recommended_action: str = "", raw_artifact_path: str | None = None, details: dict[str, Any] | None = None, ) -> dict[str, Any]: return ToolResult( status="ok", evidence=evidence or [], metrics=metrics or {}, confidence=confidence, next_recommended_action=next_recommended_action, raw_artifact_path=raw_artifact_path, details=details or {}, ).to_dict() - src/heap_seance_mcp/tools.py:16-23 (helper)Imports of shell_tools helpers (require_binary, ensure_success, run_command) used by java_gc_snapshot to execute the jstat command.
from .shell_tools import ( CommandExecutionError, ToolingMissingError, ensure_success, require_any_binary, require_binary, run_command, )