【发布时间】:2015-01-03 21:50:30
【问题描述】:
我知道以下在 java 中生成线程转储的方法:
- 杀死-3
- jstack
- JVM 内部的 JMX
- JMX 远程
- JPDA(远程)
- JVMTI (C API)
在这些方法中,哪种方法对 JVM 的性能影响最小?
【问题讨论】:
标签: performance jvm thread-dump
我知道以下在 java 中生成线程转储的方法:
在这些方法中,哪种方法对 JVM 的性能影响最小?
【问题讨论】:
标签: performance jvm thread-dump
如果您只需要将所有堆栈跟踪转储到 stdout,kill -3 和 jstack 应该是最便宜的。该功能在 JVM 代码中本地实现。没有创建中间结构 - 虚拟机在遍历堆栈时会自行打印所有内容。
两个命令执行相同的 VM 操作,除了信号处理程序在本地将堆栈跟踪打印到 Java 进程的 stdout,而jstack 通过 IPC(Unix 域)接收来自目标 VM 的输出Linux 上的 socket 或 Windows 上的 Named Pipe)。
jstack 在底层使用Dynamic Attach 机制。如果您希望将堆栈跟踪作为纯字节流接收,也可以直接使用动态附加。
import com.sun.tools.attach.VirtualMachine;
import sun.tools.attach.HotSpotVirtualMachine;
import java.io.InputStream;
public class StackTrace {
public static void main(String[] args) throws Exception {
String pid = args[0];
HotSpotVirtualMachine vm = (HotSpotVirtualMachine) VirtualMachine.attach(pid);
try (InputStream in = vm.remoteDataDump()) {
byte[] buf = new byte[8000];
for (int bytes; (bytes = in.read(buf)) > 0; ) {
System.out.write(buf, 0, bytes);
}
} finally {
vm.detach();
}
}
}
请注意,所有提到的方法都在 VM 安全点中运行。这意味着在收集堆栈跟踪时所有 Java 线程都将停止。
【讨论】:
最高效的选项可能是使用 ThreadMXBean.dumpAllThreads() API,而不是请求写入磁盘的文本线程转储: http://docs.oracle.com/javase/7/docs/api/java/lang/management/ThreadMXBean.html#dumpAllThreads(boolean,%20boolean)
当然,能否使用取决于你需要线程转储文件,还是只需要数据。
【讨论】:
ThreadInfo[] 的 Java-land 表示需要大量堆内存,并且需要大量时间来构建和打印。