mcp-jvm-diagnostics 0.1.8 → 0.1.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/build/analyzers/contention.js +10 -2
- package/build/index.js +5 -5
- package/build/parsers/heap-histo.js +17 -9
- package/package.json +1 -1
|
@@ -47,14 +47,22 @@ export function analyzeContention(threads) {
|
|
|
47
47
|
recommendations.push("Multiple contention hotspots detected. Consider redesigning synchronization — ConcurrentHashMap, read-write locks, or lock-free data structures may reduce contention.");
|
|
48
48
|
}
|
|
49
49
|
// Check for thread pool exhaustion
|
|
50
|
-
const
|
|
51
|
-
for (const pattern of
|
|
50
|
+
const platformPoolPatterns = ["pool-", "http-", "exec-", "ForkJoin", "worker-"];
|
|
51
|
+
for (const pattern of platformPoolPatterns) {
|
|
52
52
|
const poolThreads = threads.filter(t => t.name.includes(pattern));
|
|
53
53
|
const poolBlocked = poolThreads.filter(t => t.state === "BLOCKED");
|
|
54
54
|
if (poolThreads.length > 0 && poolBlocked.length > poolThreads.length * 0.5) {
|
|
55
55
|
recommendations.push(`Thread pool "${pattern}*" has ${poolBlocked.length}/${poolThreads.length} threads BLOCKED — pool exhaustion risk. Consider increasing pool size or reducing lock hold time.`);
|
|
56
56
|
}
|
|
57
57
|
}
|
|
58
|
+
// Virtual thread schedulers (Java 21+ VirtualThreadScheduler, Kotlin coroutines DefaultDispatcher).
|
|
59
|
+
// BLOCKED/WAITING state in these pools does not exhaust OS carrier threads — add a caveat instead
|
|
60
|
+
// of triggering the same exhaustion warning.
|
|
61
|
+
const virtualPoolPatterns = ["VirtualThreadScheduler", "DefaultDispatcher"];
|
|
62
|
+
const hasVirtualPool = threads.some(t => virtualPoolPatterns.some(p => t.name.includes(p)));
|
|
63
|
+
if (hasVirtualPool) {
|
|
64
|
+
recommendations.push("Virtual thread pool detected. BLOCKED and WAITING states do not exhaust OS carrier threads — monitor task queue depth and carrier thread saturation instead.");
|
|
65
|
+
}
|
|
58
66
|
// Check for WAITING threads that might indicate starvation
|
|
59
67
|
const waitingCount = threads.filter(t => t.state === "WAITING").length;
|
|
60
68
|
if (waitingCount > totalThreads * 0.7) {
|
package/build/index.js
CHANGED
|
@@ -13,7 +13,7 @@ import { parseJfrSummary } from "./parsers/jfr-summary.js";
|
|
|
13
13
|
import { generateReportFromThreadDump, analyzeThreadDumpMarkdown, } from "./reporting.js";
|
|
14
14
|
// Handle --help
|
|
15
15
|
if (process.argv.includes("--help") || process.argv.includes("-h")) {
|
|
16
|
-
console.log(`mcp-jvm-diagnostics v0.1.
|
|
16
|
+
console.log(`mcp-jvm-diagnostics v0.1.9 — MCP server for JVM diagnostics
|
|
17
17
|
|
|
18
18
|
Usage:
|
|
19
19
|
mcp-jvm-diagnostics [options]
|
|
@@ -33,7 +33,7 @@ Tools provided:
|
|
|
33
33
|
}
|
|
34
34
|
const server = new McpServer({
|
|
35
35
|
name: "mcp-jvm-diagnostics",
|
|
36
|
-
version: "0.1.
|
|
36
|
+
version: "0.1.9",
|
|
37
37
|
});
|
|
38
38
|
// --- Tool: analyze_thread_dump ---
|
|
39
39
|
server.tool("analyze_thread_dump", "Parse a JVM thread dump (jstack output) and analyze thread states, detect deadlocks, identify lock contention hotspots, and find thread starvation patterns. Handles both platform threads and virtual threads (Java 21+). Note: deadlock detection covers synchronized monitor locks only — java.util.concurrent.locks.ReentrantLock and other j.u.c lock types do not expose their waiters in thread dump lock info and will not be detected.", {
|
|
@@ -345,15 +345,15 @@ server.tool("analyze_jfr", "Parse JDK Flight Recorder summary output and analyze
|
|
|
345
345
|
}
|
|
346
346
|
});
|
|
347
347
|
// --- Tool: diagnose_jvm ---
|
|
348
|
-
server.tool("diagnose_jvm", "Unified JVM diagnosis combining thread dump and GC log analysis.
|
|
348
|
+
server.tool("diagnose_jvm", "Unified JVM diagnosis combining thread dump and GC log analysis with cross-correlation. Detects deadlocks, lock contention, GC pressure, and GC-induced cascading thread blocks. When both inputs are provided from the same time window, cross-correlates high GC overhead with contention and flags long GC pauses causing thread starvation. Either input can be omitted for single-source analysis.", {
|
|
349
349
|
thread_dump: z
|
|
350
350
|
.string()
|
|
351
351
|
.optional()
|
|
352
|
-
.describe("Thread dump text (from jstack)"),
|
|
352
|
+
.describe("Thread dump text (from jstack, kill -3, or VisualVM). Capture at the same time as the GC log for accurate cross-correlation."),
|
|
353
353
|
gc_log: z
|
|
354
354
|
.string()
|
|
355
355
|
.optional()
|
|
356
|
-
.describe("GC log text (from -Xlog:gc*)"),
|
|
356
|
+
.describe("GC log text (from -Xlog:gc* for Java 9+, or -verbose:gc for Java 8). Capture at the same time as the thread dump for accurate cross-correlation."),
|
|
357
357
|
}, async ({ thread_dump, gc_log }) => {
|
|
358
358
|
try {
|
|
359
359
|
if (!thread_dump && !gc_log) {
|
|
@@ -56,7 +56,9 @@ export function parseHeapHisto(text) {
|
|
|
56
56
|
});
|
|
57
57
|
return { entries, totalInstances, totalBytes, issues, recommendations };
|
|
58
58
|
}
|
|
59
|
-
// Analyze top entries for
|
|
59
|
+
// Analyze top entries for heap-percentage-based issues.
|
|
60
|
+
// These checks are only meaningful near the top of the list — a class that doesn't
|
|
61
|
+
// rank in the top 30 by bytes cannot be consuming >10% of heap.
|
|
60
62
|
for (const entry of entries.slice(0, 30)) {
|
|
61
63
|
const pctBytes = totalBytes > 0 ? (entry.bytes / totalBytes) * 100 : 0;
|
|
62
64
|
const isJdkInternal = JDK_INTERNALS.has(entry.className);
|
|
@@ -69,6 +71,20 @@ export function parseHeapHisto(text) {
|
|
|
69
71
|
});
|
|
70
72
|
recommendations.push(`Investigate ${entry.className} — use Eclipse MAT or VisualVM to trace retention paths. Check for unbounded caches or collections.`);
|
|
71
73
|
}
|
|
74
|
+
// Char arrays ([C) or byte arrays ([B) dominating — usually String-related
|
|
75
|
+
if ((entry.className === "[B" || entry.className === "[C") && pctBytes > 40) {
|
|
76
|
+
issues.push({
|
|
77
|
+
severity: "WARNING",
|
|
78
|
+
message: `${entry.className === "[B" ? "Byte" : "Char"} arrays consume ${pctBytes.toFixed(1)}% of heap — likely driven by String retention. Check for large string caches or log buffering.`,
|
|
79
|
+
className: entry.className,
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
// Instance-count checks scan all entries: a class ranked outside the top 30 by bytes
|
|
84
|
+
// can still have an excessive number of small instances (e.g., many small DTOs or events).
|
|
85
|
+
for (const entry of entries) {
|
|
86
|
+
const pctBytes = totalBytes > 0 ? (entry.bytes / totalBytes) * 100 : 0;
|
|
87
|
+
const isJdkInternal = JDK_INTERNALS.has(entry.className);
|
|
72
88
|
// Very high instance count for non-JDK class (> 100K)
|
|
73
89
|
if (entry.instances > 100_000 && !isJdkInternal && pctBytes <= 10) {
|
|
74
90
|
issues.push({
|
|
@@ -86,14 +102,6 @@ export function parseHeapHisto(text) {
|
|
|
86
102
|
});
|
|
87
103
|
recommendations.push("Replace finalize() with Cleaner or try-with-resources. Finalizers delay GC and can cause memory pressure.");
|
|
88
104
|
}
|
|
89
|
-
// Char arrays ([C) or byte arrays ([B) dominating — usually String-related
|
|
90
|
-
if ((entry.className === "[B" || entry.className === "[C") && pctBytes > 40) {
|
|
91
|
-
issues.push({
|
|
92
|
-
severity: "WARNING",
|
|
93
|
-
message: `${entry.className === "[B" ? "Byte" : "Char"} arrays consume ${pctBytes.toFixed(1)}% of heap — likely driven by String retention. Check for large string caches or log buffering.`,
|
|
94
|
-
className: entry.className,
|
|
95
|
-
});
|
|
96
|
-
}
|
|
97
105
|
}
|
|
98
106
|
// Check for class loader leak indicators
|
|
99
107
|
const classCount = entries.find(e => e.className === "java.lang.Class");
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "mcp-jvm-diagnostics",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.10",
|
|
4
4
|
"description": "MCP server for JVM diagnostics — analyze thread dumps, detect deadlocks, parse GC logs, and get JVM tuning recommendations",
|
|
5
5
|
"mcpName": "io.github.dmitriusan/mcp-jvm-diagnostics",
|
|
6
6
|
"author": "Dmytro Lisnichenko",
|