Java Diagnostics
GitHubOfficialFirst committed by jduboisDistributed by GitHub
- Skill
- Guidelines
- Software development
- MIT
- No issues found
AutoGineer summary
Written by AutoGineer from the skill’s own files, not by the author
This skill provides a structured, safety-conscious approach to diagnosing common JVM performance issues. It categorizes diagnostic tools into three permission tiers based on their intrusiveness and potential impact on production systems. By following a symptom-first decision table, users can systematically identify and resolve issues such as high CPU usage, memory leaks, thread starvation, and GC pauses. The skill emphasizes safe data collection, user consent for sensitive operations, and local analysis of diagnostic artifacts.
What it does
- Provides a decision table mapping common JVM symptoms to specific diagnostic tools.
- Defines three tiers of diagnostic operations based on safety and intrusiveness.
- Offers guidance on using JDK tools like jcmd, jstack, jmap, and JFR.
- Includes instructions for profiling with async-profiler and analyzing native memory.
- Outlines best practices for diagnosing JVM issues within containerized environments.
- Establishes a workflow for capturing, analyzing, and cleaning up diagnostic data.
When to use it
- When a Java application experiences high CPU, memory leaks, or OutOfMemoryErrors.
- When investigating slow startup times or unexplained latency in requests.
- When diagnosing thread-related issues like deadlocks or thread starvation.
- When analyzing long GC pauses or native memory growth.
- When a JVM crashes or hangs and requires post-mortem analysis.
Advantages
- Promotes safe diagnostic practices by enforcing permission tiers.
- Reduces trial-and-error by providing a symptom-based diagnostic path.
- Minimizes production impact by prioritizing non-intrusive tools first.
- Provides clear guidance on handling sensitive data in heap dumps.
- Standardizes the diagnostic process across different JVM environments.
Usage examples
- “My Java application is experiencing high CPU usage. How should I start diagnosing it?”
- The agent will guide you to capture thread dumps using Tier 1 tools and map them to native thread IDs, followed by using JFR or async-profiler for a CPU flame graph.
- “I suspect a memory leak in my production JVM. What is the safe way to investigate?”
- The agent will instruct you to use Tier 2 tools like jstat and class histograms first, and only proceed to Tier 3 heap dumps with explicit consent and proper precautions.
- “How do I diagnose native memory growth in a containerized Java app?”
- The agent will suggest comparing RSS versus heap usage, enabling Native Memory Tracking (NMT), and using async-profiler's nativemem mode.
Install
Download the skill as a ZIP:
https://autogineer.com/agent-skills/github/java-diagnostics/downloadUnzip it into the cross-client skills folder of your project:
mkdir -p .agents/skills && unzip java-diagnostics.zip -d .agents/skills
Documentation by jdubois
Java Diagnostics
Pick the lightest tool that answers the question, starting from the symptom.
Permission tiers (obey them)
| Tier | Tools | Rule |
|---|---|---|
| 1. Read-only | jps -l, jcmd <pid> help/VM.version/VM.flags/Thread.print, jstat, jstack, reading logs | May run after stating the exact command. Class histograms (jcmd <pid> GC.class_histogram, jmap -histo, jmap -histo:live) are NOT Tier 1: they run heap inspection at a safepoint and can pause application threads on a large heap, so treat them as Tier 2 (consent, stated overhead). The default forms and -histo:live additionally force a full GC; -all=true / jmap -histo skip the full GC but still pause during the scan (and count unreachable objects). |
| 2. Recording / attach | JFR (JFR.start, -XX:StartFlightRecording), async-profiler, NMT (-XX:NativeMemoryTracking), enabling GC logs | Requires user consent. State duration and expected overhead (JFR default profile is about 1-2%; async-profiler depends on mode; NMT summary roughly 5-10%, detail more) before running. |
| 3. Intrusive / sensitive | Heap dumps (GC.heap_dump, jmap -dump), jhsdb, commands that print JVM arguments or system properties (jps -v/-lv/-m, bare jcmd, VM.system_properties, VM.command_line, jinfo, ps aux on a Java process; they can expose secrets, redact output), JDWP with suspend, anything on production | Requires explicit consent, a stated target path, free-disk check (a dump is about the size of the used heap), and a stated pause. Heap dumps contain secrets (passwords, tokens, personal data). Never share or upload them; redaction is NOT a reliable safeguard. Analyze locally and delete afterwards. |
Never run Tier 2 or Tier 3 commands against production unless the user explicitly instructs it. Run diagnostic tools as the same OS user as the target JVM. Prefer reproducing on dev or staging.
Decision table
| Symptom | First step | Then | Reference |
|---|---|---|---|
| High CPU | Thread dumps x3 (Tier 1) + top -H to map hot native thread ids to nid | JFR or async-profiler CPU flame graph (Tier 2) | threads, jfr, async-profiler |
| Memory leak / OOM | jstat -gcutil, GC.class_histogram -all=true twice, minutes apart (Tier 2: safepoint pause even with -all=true; without it a full GC too; get consent on production) | Heap dump + Eclipse MAT (Tier 3) or JFR OldObjectSample (Tier 2) | heap, gc |
| Slow startup | -Xlog:class+load, framework startup/condition reports, timestamped logs | JFR from start, async-profiler wall-clock | jfr, async-profiler |
| Deadlock / thread starvation | jcmd <pid> Thread.print (reports deadlocks), compare dumps over time | Virtual threads: Thread.dump_to_file | threads |
| GC pauses | GC log (-Xlog:gc*) and jstat -gc | JFR GC events; tune collector/heap | gc |
| Native memory growth (RSS grows, heap does not) | Compare RSS vs heap; enable NMT, jcmd VM.native_memory baseline / summary.diff (Tier 2) | async-profiler nativemem or allocator tools | nmt, containers |
| Slow requests | Tracing/metrics and logs first; Actuator or Dev UI (see below) | JFR (socket/file/lock events), async-profiler wall-clock | jfr, async-profiler |
| JVM crash / hang, no tools respond | hs_err_pid*.log, core dump | jhsdb (Tier 3) | basics |
Start with jps/jcmd basics to identify the target JVM and confirm which JDK version is running.
Workflow
Capture the symptom precisely (when, how often, since which change, JDK version, container limits).
Choose the tier needed; state the command, its overhead, and output location, and get consent for Tier 2/3.
Collect data to a dedicated directory, with timestamps. Prefer several samples over one.
Form a hypothesis from the data, then confirm with a second source (for example a thread dump plus a flame graph).
Fix, re-measure with the same method, and clean up artifacts (dumps, recordings).
Application-level insights (optional)
JDK tools see the JVM; some questions (which endpoint, which SQL query, which bean) are easier at the application level. Optional options, in order of preference:
Spring Boot Actuator (
metrics,health,loggers,httpexchanges) and Quarkus Dev UI / Micrometer metrics are built in and need no extra tool. Expose Actuator endpoints minimally; Forheapdumpandthreaddump, follow the policy in thespring-observabilityskill: never expose them over public HTTP; the only exception is a temporary, user-consented window with authentication, TLS and network restriction, removed afterwards.BootUI (https://github.com/jdubois/boot-ui , https://www.julien-dubois.com/boot-ui/): a local-only developer console with an opt-in MCP server for Spring Boot and Quarkus. Optional. Its skill can be installed with
gh skill install jdubois/boot-ui skills/bootui.
If considering BootUI:
Ask the user for consent before adding any dependency or installing the skill.
Use it in a local/dev profile only; never expose it on a network, and never enable its heap dump, thread dump endpoints or MCP server in production.
Check the capability and version first (read its README for the supported Spring Boot / Quarkus versions) instead of assuming features.
Follow the project's own documentation for usage; this skill does not reproduce it.
Containers
See containers for attaching tools inside containers, -XX:MaxRAMPercentage, and cgroup memory limits.
References
Debugger-based investigation: the
java-debuggingskill.
Official docs (prefer them over this skill for the JDK in use; change 21 to your version): jcmd https://docs.oracle.com/en/java/javase/21/docs/specs/man/jcmd.html, jfr https://docs.oracle.com/en/java/javase/21/docs/specs/man/jfr.html, JFR guide https://docs.oracle.com/en/java/javase/21/jfr/introduction-jdk-flight-recorder.html, troubleshooting guide https://docs.oracle.com/en/java/javase/21/troubleshoot/, async-profiler releases https://github.com/async-profiler/async-profiler/releases.
Files
- ATTRIBUTION.mdAdded by AutoGineer863 B
- LICENSELicence file added by AutoGineer1.0 KiB
- SKILL.md7.2 KiB
- references/async-profiler.md3.0 KiB
- references/containers.md1.7 KiB
- references/gc.md1.6 KiB
- references/heap.md3.0 KiB
- references/jcmd-basics.md1.9 KiB
- references/jfr.md2.3 KiB
- references/native-memory.md1.5 KiB
- references/thread-dumps.md3.3 KiB
references/heap.md
Heap, histograms, Eclipse MAT
Tier 2: class histogram (no full GC with -all=true, but still a safepoint pause)
jcmd <pid> GC.class_histogram -all=true | head -40 # no GC; includes unreachable objects
jmap -histo <pid> | head -40 # no GC
jcmd <pid> GC.class_histogram | head -40 # full GC, live objects only
jmap -histo:live <pid> | head -40 # full GC, live objects onlyAll four run heap inspection at a safepoint, which can pause application threads for the duration of the scan on a large heap: on production, get explicit consent and state the overhead first. The last two also force a full GC. The first two avoid the full GC but may count garbage that is not yet collected. Take two histograms several minutes apart under load; classes whose instance count and bytes keep growing are leak suspects.
Tier 3: heap dump (explicit consent required)
Before running: state the target path, check free disk (df -h; roughly the used heap size), and warn of a stop-the-world pause proportional to heap size. Write to a restricted directory (chmod 700).
jcmd <pid> GC.heap_dump /secure/dir/heap.hprof # live objects only (full GC)
jcmd <pid> GC.heap_dump -all=true /secure/dir/heap.hprof # include unreachable objectsjmap -dump:live,format=b,file=heap.hprof <pid> is the older equivalent. The file is written by the target JVM, so the path must be writable by it (and inside the container if containerized).
Sensitive data: a heap dump contains everything in memory: credentials, tokens, session data, personal data. Never upload or share it (including with AI services or issue trackers). Redaction is not a reliable safeguard. Analyze locally and securely delete the file when done.
Automatic dump on OOM (an opt-in startup flag, still Tier 3 because of the data and disk usage):
-XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/secure/dir/Set HeapDumpPath to a volume with enough space; in containers an unbounded dump can fill the node.
Analyze with Eclipse MAT
Install Eclipse Memory Analyzer (https://eclipse.dev/mat/) from the official download page. It needs a Java runtime and a heap of about 1.5x the dump size (edit
MemoryAnalyzer.ini,-Xmx).Open the
.hprof; run the Leak Suspects report first.Use the Dominator Tree (sorted by retained heap) to find what holds memory.
For a suspect object, Path to GC Roots, excluding weak/soft references shows why it is not collected.
Compare two dumps with the histogram comparison to confirm growth.
Common causes: unbounded caches or maps, static collections, listeners never removed, ThreadLocals in pooled threads, classloader leaks on redeploy, large result sets.
Headless parsing is available through ParseHeapDump.sh in the MAT distribution (-vmargs -Xmx...), producing report ZIPs.
Alternative (Tier 2)
JFR with jdk.OldObjectSample and path-to-gc-roots (path-to-gc-roots=true) finds leak candidates without a full dump; see jfr.
Requirements and compatibility
Written for: GitHub Copilot
Works with: Claude Code, Claude apps, OpenAI Codex, GitHub Copilot, Cursor, Gemini CLI, Kiro, OpenCode, Goose, Amp, Roo Code, JetBrains Junie, Factory Droid, Devin (ex-Windsurf), Mistral Vibe, OpenHands, Letta
“Works with” means the tool reads the open Agent Skills format; a skill written for one tool may use features others lack.
Needs: Needs an MCP server
Security
No issues found by our static scan· No issues found
A static scan is not a guarantee. Skills are third-party content: review a skill before you let an agent use it.
Attribution and licence
- First committed by
jdubois
- Publisher
- GitHub (Official)
- Distributed by
- GitHub
- Source
- github/awesome-copilot · skills/java-diagnostics · commit 797337f
- Licence
- MIT License (redistribution allowed)
- LICENSE (added by AutoGineer from LICENSE)
- ATTRIBUTION.md (written by AutoGineer)
- Synced
- Contributors
- jdubois
AutoGineer is not affiliated with or endorsed by jdubois or GitHub.
Download ZIP
The ZIP holds the skill’s files, its licence files and an ATTRIBUTION.md. Download java-diagnostics.zip