我正在尝试诊断我正在使用的 Java Web 应用程序(Jenkins)变得无响应的问题。如果我在jstack
没有-F
标志的情况下运行它不会给我任何东西,但是如果我将标志放入强制线程转储,我不仅会得到结果,而且应用程序会开始响应并继续运行,就好像什么都没发生一样,直到它最终再次停止响应。
flag会jstack -F
影响正在运行的 JVM 并导致无响应的应用程序再次开始响应?
You can see the source to jstack here. The -F argument changes how jstack connects to the jvm. With -F (or -m) JStack connects to the jvm using the java debugger interface. If a pid is specified, JStack connects with the SA PID Attaching Connector which says,
The process to be debugged need not have been started in debug mode(ie, with -agentlib:jdwp or -Xrunjdwp). It is permissable for the process to be hung.
I don't know why it would cause an unresponsive application to start responding again, but the link above also says,
The process is suspended when this connector attaches and resumed when this connector detaches.
This may have an effect.
jstack -F -l pid 类似于(假设工作目录是 JAVA_HOME)
bin/java -Dsun.jvm.hotspot.debugger.useWindbgDebugger -Dsun.jvm.hotspot.debugger.useProcDebugger -cp lib/sa-jdi.jar;lib/tools.jar sun.tools.jstack.JStack -F -l pid
if (arg.equals("-F")) {
useSA = true;
}
.....
// now execute using the SA JStack tool or the built-in thread dumper
if (useSA) {
// parameters (<pid> or <exe> <core>
...
runJStackTool(mixed, locks, params);
} else {
// pass -l to thread dump operation to get extra lock info
String pid = args[optionCount];
...
runThreadDump(pid, params);
}
由于传入了-F,调用runJStackTool加载sun.jvm.hotspot.tools.JStack,效果和直接调用一样
bin\java -Dsun.jvm.hotspot.debugger.useWindbgDebugger -Dsun.jvm.hotspot.debugger.useProcDebugger -cp lib/sa-jdi.jar;lib/tools.jar sun.jvm.hotspot.tools.JStack pid
并且 sun.jvm.hotspot.tools.JStack 将调用sun.jvm.hotspot.bugspot.BugSpotAgent attach -> go ->setupVM 方法
也许下面的代码是魔法
jvmdi = new ServiceabilityAgentJVMDIModule(debugger, saLibNames);
if (jvmdi.canAttach()) {
jvmdi.attach();
jvmdi.setCommandTimeout(6000);
debugPrintln("Attached to Serviceability Agent's JVMDI module.");
// Jog VM to suspended point with JVMDI module
resume();
suspendJava();
suspend();
debugPrintln("Suspended all Java threads.");
}
它将挂起目标进程中的所有 Java 线程。如果您的应用程序因线程饥饿而挂起,则挂起方法调用可能会放松它们。