级别: 中级 Adam Pilkington, 软件工程师, IBM, Software Group
2009 年 6 月 09 日 Java™ 应用程序出现故障时生成的工件可以帮助您分析故障的根源。Java Community Process 正在开发一个标准 API 来帮助执行后期分析,正在开发的 Apache Kato 项目将为此 API 生成参考实现和工具。本文是本系列文章的第 1 部分,主要介绍 Post mortem JVM Diagnostics API (JSR 326) 并概述 Kato 如何帮助您利用它。第 2 部分将更加深入地探索后期分析场景。
本文是本系列文章的第 1 部分,主题是介绍如何使用应用程序意外终止时生成的工件分析 Java 代码的问题。Java Specification Request (JSR) 326 正在开发之中,它将定义一个行业标准 API 来实现此操作。您将了解 Apache Kato 项目
所交付的参考实现和示例工具,以演示如何使用此 API。借助这些工具,您将能够分析各种问题,比如内存不足错误,或者只是浏览可用的工件。本文将提供关于 JSR 326 和 Kato 项目的一些背景知识,然后讨论一些常见的后期分析场景,并概述所涉及的问题。第 2 部分将更加详细地研究各个场景,扩展待解决问题,并展示如何使用 API 解决它们。
实时监控和后期分析
两个主要类别定义了如何诊断运行中的 Java 应用程序的问题。第一种类别是实时监控:您观察运行中的虚拟机的行为,比如说监控创建对象的频率以及它们在垃圾收集之前的生存期。目前存在许多开源及商业的实时监控工具(参见 参考资料)。第二种类别是后期分析。当运行中的 JVM 遇到致命错误时,它所使用的进程将终止,并且将生成一系列工件。根据错误的严重程度,JVM 可以在其关闭时创建这些工件,或者由操作系统来创建它们。后期分析就是在 JVM 出现故障后分析这些工件。
 |
生成后期工件
运行中的进程并非一定要终止才能生成后期工件,这还得取决于不同的 JVM 提供商。当您意识到在许多情况下都是 JVM 本身在创建工件时,则不难理解此进程可以在任意时间触发。这带来了有趣的诊断功能,比如说指示 JVM 创建抛出特定异常时所需的工件,然后使用适当的工具诊断异常的根源。
|
|
实时监控工具支持连接到所有 JVM 提供商都支持的大量标准 API 和接口(比如 JVM Tool Interface),因为它们是 Java 语言规范的一部分。相反,后期工件通常是不透明的数据块。典型的例子包括内核文件、堆块和各种内部格式及结构仅为供应商所知的系统块,但一些格式是公共文档。这让编写诊断工具的人难以创建仅适用于有限 JVM 实现的工具。幸运的是,社区正在努力解决这个问题。
JSR 326 和 Apache Kato
JSR 326 正在努力定义用于访问包含在后期工件中的数据的标准 API。它旨在通过 4 种方式解决 Java 社区的需求:
- 促进工具生态系统的发展,增加可用工具的数量。
- 提高不同 JVM 提供商的工具的质量和功能。
- 允许开发人员解决自己的问题,而不需要依靠第三方的支持。
- 解决影响当前分析执行方式的长期问题。
JSR 326 Expert Group 将定义 API 用于解决的问题和场景。然后,这些用户场景将用于形成 API 的外观和行为。Expert Group 将考虑一些比较有趣的设计挑战包括:
- 有效在大数据集中导航。
- 管理异常处理战略和规则,管理检测到或未检测到的异常的使用。
- 要使用的记录机制。
- 实现的可选择性。在设计用于与大量独立定义的后期工件交互的 API 时,各实例中呈现的信息应该有所区别。这意味着您必须定义一个机制,它能让 API 的实现指示所请求的信息不可用。因此,可以编写一些工具来合理地处理缺少的数据。
- 发行版之间的向后兼容性。
无论您对于后期诊断是否有特别的兴趣,我们讨论的设计基础都具备比较通用的特性,并且能为您提供帮助。无论如何,请参见 参考资料 获取所有必要的链接,以查看 JSR 326 或为其做贡献。
 |
未来问题
JSR 326 的需求之一是解决将影响后期诊断的未来问题或行业趋势。第一个问题是,已有后期工件的大小将会增加。随着计算机行业向 64 位、多核和多处理器服务器发展,工件可以包含的信息量可能会大大超过可用大容量存储器的支持。即便能够 存储它们,还需要面对处理数据或将它们发送给能处理它们的目标的后续问题。另一个问题是,当工件包含来自不同提供商的多个 JVM 的信息时,应该如何处理这种情况。
|
|
Apache Kato
Apache Kato 是将提供 JSR 326 参考实现的开源项目,用于分析 Sun 虚拟机生成的工件。代码库由 IBM 的 Diagnostic Tool Framework for Java (DTFJ) 提供支持(参见 参考资料)。作为开发中的项目,Kato 将适时成为一个功能全面的 Apache Software Foundation 项目。
Kato 并不是仅仅是一个参考实现。它还包含:
-
Technology Compatibility Kit (TCK):其他 JVM 提供商可以使用这个测试套件检测它们与 JSR 326 的兼容性水平。
-
Documentation:此 API 将可以作为 Javadoc 下载和浏览。
-
Wiki:涵盖项目所有方面的 wiki。
-
示例工具:演示使用 API 时的最佳实践,项目将提供许多可下载的工具,用于解决实际问题。
诊断工具和使用它们的场景
分析后期工件的目的是确定问题的底层根源,或者提供关于虚拟机状态的视图。接下来,我们将介绍可用于执行此分析的工具,然后讨论一些常见场景并概述所涉及的问题。
Kato 的诊断工具将具备下面一些特征:
-
交互性和批处理:工具将采用交互的方式使用,比如是作为 GUI 使用,还是像批处理中的命令行接口(CLI)那样使用?
-
启动时间或处理时间:快速启动对工具更加重要,还是数据处理性能更加重要?
-
随机或串行存储:工具采用随机还是串行方式访问后期工件?
-
轻量级或重量级:工具将访问大量可用的数据,还是选择性与较少项目交互?
表 1 显示了 Apache Kato 项目将生成的工具,使用刚才定义的特征进行分类:
表 1. Kato 工具
| 工具类型或问题区域 | 交互性(GUI)或批处理(CLI) | 启动时间或处理时间 | 随机或串行存取 | 轻量级或重量级 |
|---|
| Java Debug Interface 连接器(例如,使用 Eclipse 调试工件) | 交互性 | 启动 | 随机 | 轻量级 | | 工件管理器 | 交互性 | 启动 | 随机 | 轻量级 | | 本机内存分析 | 批处理 | 处理 | 串行 | 重量级 | | 趋势分析 | 批处理 | 启动 | 随机 | 重量级 | | 用于检测潜在问题的工件分析器 | 批处理 | 处理 | 串行 | 重量级 | | Java 堆分析器 | 交互性 | 启动 | 串行 | 重量级 |
工件管理器
您可以使用工件管理器查看后期工件的内容。一个常见的实现就是 GUI 工具在左侧以树型结构显示工件内容,并通过一些面板在右侧显示详细信息。您还可以使用管理器定位或搜索工件中的已知项目。管理器应该是轻量级的,因为它只能处理直接响应用户输入的项目,而不是迭代工件中的所有项目。管理器还应提供以下功能:
- 数据类型规范:能够通知 UI 将特定地址的数据显示为具体的数据类型。例如,此地址表示以 null 结尾的字符串的开始。
- 数据覆盖:将包含在转储中的字节值覆盖为用户定义的值,并让 UI 使用更新后的值。这表示您将能够通过指定正确的值来修复损坏的结构或列表。然后,您应该能够根据需要保存和重新加载这些覆盖值。
- 自动确定工件类型。
- 通过管理器启动其他工具。这可以是直接启动工具,或者带一组在当前管理器上下文中有用的命令行选项。举例来说,如果管理器显示堆占用了很大的空间,则您可以启动 工件分析器 来执行堆占用空间分析。
本机内存分析
过去,Java 开发人员不需要担心本机内存;事实上,JVM 的一个优势便是能帮助您解决此问题。但是现在本机内存的问题又重新成为了讨论的焦点(参见 参考资料)。最开始,本机内存的使用是相对比较简单的,因为您会在某个时候通过 Java Native Interface (JNI) 调用访问 JVM 外部的一些功能。这可以是您自己通过 JNI 发起的直接调用,或是编写到拥有良好定义的 JNI 链接的规范中的直接调用,比如 JVM Tool Interface (JVMTI)。随着 Java 5 和 java.nio 包(以及子包)的引入,本机内存作为该包提供的缓冲的底层存储使用。这很容易导致程序中拥有大量空闲 Java 堆,但会由于本机内存耗尽而抛出内存不足异常。这意味着,本机内存分析工具正在变得越重要,并且需要受 JSR 326 支持。这种工具的应用包括能够:
- 查看本机内存与 Java 对象之间的链接 — 也就是说,哪个 Java 对象消耗的内存最多。
- 列出应用程序中出现的所有 JNI 引用。
- 在已分配内存中搜索已知值。
- 查看应用程序本机内存使用情况的汇总报告。
工件分析器
工件分析器处理指定工件的完整内容,查找各种常见错误,例如多线程应用程序中的死锁线程。它们可以构成一幅 JVM 全图,在 JVM 终止时提供对其状态的统计分析。此信息可用于确定 Java 对象的数量和类型,它们可以帮助您确定 Java 堆的空间是否已耗尽。处理这些数据本身就有许多挑战,并且需要在最终的 API 设计中考虑它们。特别重要的一点是,引入对可用于检索对象的对象查询语言的支持。API 可以支持使用列表对象来改进此方法。
Java Debug Interface (JDI) 连接器
一般生成的后期工件都是硬盘上的内核文件,运行 JVM 的进程的完整内容都将写入到其中。在其他一些编程语言中,您可以将一个调度器附加到这个文件,然后使用它查看内容并初步了解出现问题的原因。Java 语言目前定义了一些接口和标准,它们定义了如何将调试器连接到运行中的 JVM。后期 JDI 连接器的作用是允许您使用这些标准接口连接到内核文件,而不用运行 JVM。这样,您便可以在 jdb、Eclipse 或 NetBeans 等标准
Java 调试器中调试工件。
帮助定义标准
虽然 JSR 和 Apache 项目已经开始,但它们都还处于早期阶段。JSR 326 和 Apache Kato 项目都在寻找人员定义一个用于分析后期工件的 API,或者为参考实现和工具贡献代码。参与 API 开发和贡献代码的机会很多。这是参与这个全新的开源项目的难得机会,它与比较成熟的 Apache Software Foundation 项目有所不同。
为 JSR 326 做贡献
JSR 326 完全是关于解决实际问题的。如果您遇到了问题,我建议您通过邮件列表与 Expert Group 共享它们。(这些关于构建该 API 的讨论将保存在与 Apache Kato 项目相关的邮件列表上;请参见 参考资料)。这样,专家组便能确保定义的 API 将考虑到所有应用和情形。它对于 Expert Group 采用最佳方法处理这些问题非常重要。他们尤其欢迎来自以下人员的反馈:
- 使用后期诊断的人员(比如说故障查看人员或堆管理人员)。专家组希望了解您需要解决的问题类型,以及您所使用的工具。了解工具是否能实际解决问题也是很有用的(以及为何不能解决问题)。
- 后期诊断工具提供商(商业和开源应用程序)。关于您为 Java 开发创建诊断工具的体验以及希望标准 API 能解决哪些问题的反馈是很有价值的。
您还可以加入专家组,但需要具备规范指定领域的一些知识。
为 Apache Kato 做贡献
您现在已经知道,Apache Kato 项目并不仅仅是 JSR 326 的一个参考实现。它还包括使用 API 的最佳实践,以及一个 wiki 和其他文档资源。如果您希望为此项目做贡献,我建议您上网了解当前正在开发哪些项目,以及哪些领域明确需要帮助(参见 参考资料)。
结束语
我希望本文能够让您了解 JSR 326 和 Kato 涵盖的一些方面。一些相关方面更加具有通用性,但不属于本文的讨论范围。还需要考虑的一些方面包括:
- 处理大量数据,确保实现良好的性能,并且最终解决方案能够按需执行。这将涉及到传输和扫描数据等。
- 开发缓存策略和它们的后续实现。
- 使用轻量级、延迟加载的对象确保性能。
- 能够整合一种对象查询语言。
本系列的第二篇文章将探究各种后期分析场景,以及如何使用 Apache Kato 项目提供的各种工具和技术解决它们。此外,还将深入讨论项目如何利用 JSR 326 实现所需的结果,同时解决第 1 部分讨论的基本问题,比如大数据集导航。
参考资料 学习
获得产品和技术
讨论
关于作者  | |  | Adam Pilkington 是 IBM Java Technology Centre 的 Java 性能分析师,主要关注 Java 6 的 WebSphere Application Server 性能。在 2006 年加入 IBM 之前,他是英国一家大型金融服务组织的 J2EE 技术架构师。他拥有数学和计算机科学学位。
|
对本文的评价
|