Answers:
正如ckhan所提到的,jstack
它之所以出色,是因为它提供了JVM中所有活动线程的完整堆栈跟踪。可以使用SIGQUIT在JVM的stderr上获得相同的结果。
另一个有用的工具是jmap
可以使用进程的PID从JVM进程获取堆转储:
jmap -dump:file=/tmp/heap.hprof $PID
可以使用类似的工具加载该堆转储visualvm
(该工具现在是标准Oracle java sdk安装的一部分,名为jvisualvm)。此外,VisualVM可以连接到正在运行的JVM,并显示有关JVM的信息,包括显示内部CPU使用率,线程数和堆使用率的图表-非常适合跟踪泄漏。
另一个工具jstat
可以在一段时间内收集JVM的垃圾回收统计信息,就像使用数字参数(例如vmstat 3
)运行时的vmstat一样。
最后,可以在加载时使用Java代理对所有对象的所有方法进行检测。该库javassist
可以使此操作变得非常容易。因此,添加您自己的跟踪是可行的。困难的部分是找到一种仅在您需要时而不是一直获取跟踪输出的方法,这可能会降低JVM进行爬网的速度。有一个称为的程序dtrace
,其工作方式如下。我已经尝试过了,但是不是很成功。请注意,代理无法检测所有类,因为引导Java虚拟机所需的那些类已在其可以检测之前加载,然后为这些类添加检测为时已晚。
我的建议 -从VisualVM开始,看看是否可以告诉您您需要知道什么,因为它可以显示JVM的当前线程和重要统计信息。
在调试Linux系统上出现问题的程序时,同样徒劳的是,您可以使用类似的工具来调试系统上正在运行的JVM。
与相似top
,您可以使用jvmtop来查看系统上正在运行的JVM中包含哪些类。安装后,您可以像这样调用它:
$ jvmtop.sh
其输出具有类似工具的样式top
:
JvmTop 0.8.0 alpha amd64 8 cpus, Linux 2.6.32-27, load avg 0.12
http://code.google.com/p/jvmtop
PID MAIN-CLASS HPCUR HPMAX NHCUR NHMAX CPU GC VM USERNAME #T DL
3370 rapperSimpleApp 165m 455m 109m 176m 0.12% 0.00% S6U37 web 21
11272 ver.resin.Resin [ERROR: Could not attach to VM]
27338 WatchdogManager 11m 28m 23m 130m 0.00% 0.00% S6U37 web 31
19187 m.jvmtop.JvmTop 20m 3544m 13m 130m 0.93% 0.47% S6U37 web 20
16733 artup.Bootstrap 159m 455m 166m 304m 0.12% 0.00% S6U37 web 46
另一种选择是使用jvmmonitor。JVM Monitor是与Eclipse集成在一起的Java分析器,用于监视Java应用程序的CPU,线程和内存使用情况。您可以使用它在本地主机上自动查找正在运行的JVM,也可以使用port @ host连接到远程JVM。
当调试JVM问题时,visualvm可能是“工具”。它的功能集非常深入,您可以深入了解内部。
分析应用程序性能或分析内存分配:
获取并显示线程转储:
如果您使用的是RHEL OpenJDK(或类似的意思是它不是Oracle的JDK),则可以使用SystemTap。
有些探头使用java命令行选项启用-XX:+DTraceMethodProbes
,-XX:+DTraceAllocProbes
,-XX:+DTraceMonitorProbes
。请注意,启用这些探针将显着影响程序性能。
这是示例SystemTap脚本:
#!/usr/bin/stap
probe hotspot.class_loaded {
printf("%12s [???] %s\n", name, class);
}
probe hotspot.method_entry,
hotspot.method_return {
printf("%12s [%3d] %s.%s\n", name, thread_id, class, method);
}
probe hotspot.thread_start,
hotspot.thread_stop {
printf("%12s [%3d] %s\n", name, id, thread_name);
}
probe hotspot.monitor_contended_enter,
hotspot.monitor_contended_exit {
printf("%12s [%3d] %s\n", name, thread_id, class);
}
您也可以jstack()
用来获取该过程的Java堆栈,但是只有在 JVM 之前启动SystemTap时,它才起作用。
请注意,SystemTap将跟踪所有方法。它也无法获取方法的参数。另一种选择是使用JVM自己的跟踪功能,称为JVMTI。BTrace是最著名的JVMTI实现之一。