如何跟踪Java程序?


25

作为系统管理员,我有时会遇到程序运行异常的情况,而根本不会产生错误或没有意义的错误消息。

过去-在Java出现之前-有两种对策:

  1. 如果没有其他帮助-RTFM ;-)
  2. 如果甚至没有帮助1.跟踪系统调用并查看发生了什么

我通常strace -f在Linux上使用此任务(其他OS具有类似的跟踪工具)。现在,尽管这通常适用于任何老式程序,但在java -process 上进行跟踪时,跟踪变得非常模糊。如此众多的系统调用似乎与任何实际操作都不相关,以至于无法通过此类转储进行搜索。

有没有更好的方法可以做到这一点(如果源代码不可用)?

Answers:


16

正如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的当前线程和重要统计信息。


顺便说一句,这是一个了不起的问题。我希望更多的人添加其他想法的答案。当我问过使用Java多年的人们有关跟踪时,他们给了我空白。也许他们只是不知道strace的强大之处。
2013年

10

在调试Linux系统上出现问题的程序时,同样徒劳的是,您可以使用类似的工具来调试系统上正在运行的JVM。

工具#1-jvmtop

与相似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

工具#2-jvmmonitor

另一种选择是使用jvmmonitor。JVM Monitor是与Eclipse集成在一起的Java分析器,用于监视Java应用程序的CPU,线程和内存使用情况。您可以使用它在本地主机上自动查找正在运行的JVM,也可以使用port @ host连接到远程JVM。

jvmmonitor的ss

工具#3-visualvm

当调试JVM问题时,visualvm可能是“工具”。它的功能集非常深入,您可以深入了解内部。

分析应用程序性能或分析内存分配:

visualvm#2的ss

获取并显示线程转储:

visualvm#3的ss

参考文献



2

如果您使用的是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实现之一。


0

建议您尝试一下Jackplay,这是一个JVM跟踪工具,可让您跟踪方法的入口和出口,而无需更改或重新部署代码。


您不能将其附加到正在运行的JVM。除此之外-有趣的工具
Nils
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.