3. jstack (sun.tools.jstack)
了解 Java 进程及其对应的执行线程内部发生的情况是一种常见的诊断挑战。例如,当一个应用程序突然停止进程时,很明显出现了资源耗尽,但是仅通过查看代码无法明确知道何处出现资源耗尽,且为什么会发生。
jstack 是一个可以返回在应用程序上运行的各种各样线程的一个完整转储的实用程序,您可以使用它查明问题。
采用期望进程的 VMID 运行 jstack 会产生一个堆转储。就这一点而言,jstack 与在控制台窗口内按 Ctrl-Break 键起同样的作用,在控制台窗口中,Java 进程正在运行或调用 VM 内每个 Thread 对象上的 Thread.getAllStackTraces() 或 Thread.dumpStack()。jstack 调用也转储关于在 VM 内运行的非 Java 线程的信息,这些线程作为 Thread 对象并不总是可用的。
jstack 的 -l 参数提供了一个较长的转储,包括关于每个 Java 线程持有锁的更多详细信息,因此发现(和 squash)死锁或可伸缩性 bug 是极其重要的。
4. jmap (sun.tools.jmap)
有时,您正在处理的问题是一个对象泄露,如一个 ArrayList (可能持有成千上万个对象)该释放时没有释放。另一个更普遍的问题是,看似从不会压缩的扩展堆,却有活跃的垃圾收集。
当您努力寻找一个对象泄露时,在指定时刻对堆及时进行拍照,然后审查其中内容非常有用。jmap 通过对堆拍摄快照来提供该功能的第一部分。然后您可以采用下一部分中描述的 jhat 实用程序分析堆数据。
与这里描述的其他所有实用程序一样,使用 jmap 非常简单。将 jmap 指向您希望拍快照的 Java 进程的 VMID,然后给予它部分参数,用来描述产生的结果文件。您要传递给 jmap 的选项包括转储文件的名称以及是否使用一个文本文件或二进制文件。二进制文件是最有用的选项,但是只有当与某一种索引工具 结合使用时 — 通过十六进制值的文本手动操作数百兆字节不是最好的方法。
随意看一下 Java 堆的更多信息,jmap 同样支持 -histo 选项。-histo 产生一个对象文本柱状图,现在在堆中大量引用,由特定类型消耗的字节总数分类。它同样给出了特定类型的总示例数量,支持部分原始计算,并猜测每个实例的相对成本。
不幸的是,jmap 没有像 jstat 一样的 period-and-max-count 选项,但是将 jmap(或 jmap.main())调用放入 shell 脚本或其他类的循环,周期性地拍摄快照相对简单。(事实上,这是加入 jmap 的一个好的扩展,不管是作为 OpenJDK 本身的源补丁,还是作为其他实用程序的扩展。)