JVM 统计信息
JVM 提供许多统计信息。这些统计信息涉及诸如即时 (JIT) 编译、类加载、内存分配以及最有趣的垃圾收集之类基本的 JVM 特性。
即时编译
JVM 可将字节代码即时编译为机器代码。该动作类似于像您用于脚本语言的解释器(如 Perl)所执行的动作。但是它更先进,提供许多优化措施,使得已解释的字节代码几乎与预编译的代码运行得一样快(有时更快)。显然,执行 JIT 编译需要开销。度量应用程序需要多大开销的两个有用的统计信息是 JIT 编译次数和执行这些编译花费的时间总量。(有关 JIT 编译的更多详细信息,请参阅 参考资料。)
类加载
JVM 负责从应用程序的类使用的库向应用程序和类中加载类。因此,这些类可能是从已部署在 Geronimo 中的 WAR 或 EAR 中加载的类,也可能是包含在 WAR 或 EAR 中的 JAR 文件,或者是由 Geronimo 容器加载的 JAR 中的类。如果类不用于延长的时间,则 JVM 还可以选择卸载这些类。这将导致几项重要的统计信息:加载的类的数量、卸载的类的数量、加载和卸载类花费的时间。
内存(堆)分配
在 Java 技术中没有 malloc()
函数,这是因为 JVM 可自动为对象分配内存。对象从堆中分配;因此,使用的和空闲的堆内存数量是两个非常重要的统计信息。监视堆分配是检测可怕的内存泄漏最简单的方法之一。
垃圾收集
这可能是 JVM 最有趣的统计信息。正像 JVM 为对象分配内存一样,它还回收不再使用的对象上的内存。关于垃圾收集如何工作,包括您可以指示 JVM 用于其垃圾收集器的不同算法,有很多有趣的读物。
还有许多关于垃圾收集器本身的有趣的统计信息。首先是调用垃圾收集器的频率和垃圾收集过程中花费的时间。垃圾收集的开销很大,因为本质上它会中止应用程序的执行以便可以检验对象。显然,大量的垃圾收集可以真正减慢应用程序的运行速度。
其他有趣的统计信息与对象分代有关。垃圾收集器按代对对象进行分类,每代都指示对象已经经历了一定次数的垃圾收集。(经历很多次垃圾收集的对象比未经历或者经历了很少次数垃圾收集的对象被垃圾收集的可能性更小。)这样的对象分类允许垃圾收集器检验更少的对象,使每次垃圾收集速度更快。因此,每代中对象的数量可能相当有趣,提供更好的方法来查找内存泄漏和很好的方法来考察潜在优化(如对象缓存和对象池)的影响。
|
访问 JVM 统计信息
有几个可用的 JVM 实现,但最常见的是 Sun 的 HotSpot JVM(有关技术链接,请参阅 参考资料)。从 Java 2 Platform, Standard Edition (J2SE) 1.4.2 开始,HotSpot 进行了全面配备,提供许多上面描述的有用的统计信息。有好几个方法用于获得和分析这一数据。获得 JVM 生成的统计信息之后,您可以访问 Geronimo 的 JVM 并分析您的应用程序。
访问方法
获得一些 JVM 统计信息的最简单的方法是通过命令行。HotSpot 识别许多命令行选项,其中几个选项允许您定制堆大小和垃圾收集选项。也可以使用 -verbose:gc
选项。这可使 JVM 打印出以下形式的行:
[GC 70333K->65666K(98896K), 0.0007817 secs]
[Full GC 65666K->59333K(98896K), 0.0205250 secs]
上面示例中的第一行指示发生了一次垃圾收集。收集之前堆上使用了 70,333KB,收集之后使用了 65,666KB。第一行还指示总共有 98,896KB 的可用空间。最后,指出垃圾收集花费的时间,也即应用程序中止的时间量。第二行指示相同的信息,但表示一个完整的垃圾收集。完整的垃圾收集涉及 JVM 对堆上所有的对象进行检验,包括经历了许多代、在部分垃圾收集上不会被分析的对象。
有关更详细的信息,请使用 -XX:+PrintGCDetails
和 -XX:+PrintGCTimeStamps
选项。这些选项提供关于堆上对象的不同代的详细信息。
对于看上去更为有趣的统计信息,可以使用专门的工具。开放源码的工具和商业工具都可以使用。还可以使用 Sun 提供的一些用于与 HotSpot 一起使用的工具。jvmstat
项目包含几个用于监视 JVM 统计信息的工具,包括一个叫做 Visual Garbage Collector 或 visualgc
的图形工具, 它使用起来相对简单。您需要 Java 5 或更高版本来运行 jvmstat
,尽管它可以附加和监视 1.4.2 或更高版本的 JVM。只需下载和解压即可(有关下载链接,请参阅 参考资料)。将它添加到您的路径,即可准备运行。启动了 Java 进程时,请使用 jps
工具来通过键入 jps
标识其 JVM。它向您提供一个正在运行的 Java 进程的列表,这些进程以其 JVM 作为 ID。然后使用您想监视的进程的 ID 调用 visualgc
。jvmstat
发行版包括一个用于调用 visualgc
的 shell 脚本。如果安装了 cygwin
这样的工具,就可以在 *nix 或 Microsoft® Windows® 上调用 visualgc
了。此外,也可以按以下方式调用它:
java -Xbootclasspath/p:%JAVA_HOME%\lib\tools.jar -jar %JVMSTAT_HOME%\jars\visualgc.jar 316
其中 JAVA_HOME
环境变量指定安装 JDK 的位置,而 JVMSTAT_HOME
指示安装 jvmstat
包的位置。该行末尾的 316 是您想监视的 JVM 的 ID。该 jvmstat
包还包括一个 jstat 工具。它提供在 visualgc
中看到的绝大部分相同信息,只不过将其作为文本输出。这对收集统计信息而言至关重要,然后可以将这些统计信息拖入另一个程序,以对其进行深入分析、生成有关它的报告,等等。本文集中讨论使用 visualgc
对这些统计信息进行可视化。
清单 1 提供一个短程序,您可以运行来测试使用 jvmstat
进行监视。
|
这是一个简单的程序。它使用了泛型,所以您需要 Java 5 。如果愿意,您可以容易地改变它以不使用泛型,然后它将用较旧的 JDK 运行。它通过创建可随机调整大小的长整数数组导致内存分配。它通过随机将这些数组的一部分(大约 20%)放入一个列表来模拟内存泄漏。因此,垃圾收集器可以回收在每个循环上分配的大多数内存,但它不能回收添加到列表中的数组。您可以试验一些参数,比如睡眠大小和最大块大小。它还可以接收命令行参数,所以您可以容易地告知它要执行多少次循环。
编译 StatGen
之后,您可以简单地从 java StatGen 100
开始。这执行 100 次循环。记住,您可以在命令行指定最小和最大堆大小。采用不同的最小和最大堆大小在运行 visualgc
时将产生截然不同的视觉效果。您还可以指定不同的垃圾收集算法;用 visualgc
监视 StatGen
时,将很好地理解这些算法的区别。
图 1 展示了一些用 StatGen
运行 visualgc
的示例输出。
图 2 展示了最有趣的窗口。它首先展示了 JIT 编译。在本例中,只有三个窗口,这对于这样一个简单的示例来说并不稀奇。它还展示了类加载器信息 —— 再说一遍,这很简单,因为应用程序太简单了。
接着,它展示了总体的垃圾收集统计信息。您会看到 123 次收集和进行垃圾收集所花费的总时间约为 0.3 秒。从第一个图形中,您可以看到应用程序运行了大约 100 秒,所以进行垃圾收集花费了该时间的 0.3%。
还有关于不同分代的统计信息。Eden 空间显示了从未通过垃圾收集的新对象。示例代码生成许多这样的新对象,并且它们很快就被收集掉。
注意两个 Survivor 空间。它们基本上是较小的经历过少数几次垃圾收集的对象集。所有对象要么是立即准备收集的,要么是从未准备收集的,所以,如果它们到了 Survivor 空间,就将很快改变这种状态。
接下来是较老的一代。这些对象经历了大量垃圾收集。您可以看到稳定的对象增加,表明存在潜在的内存泄漏。最后,您看到的是 JVM 确定永远不会被收集的对象的永久代。
直方图窗口(参见 图 3)展示了关于 Survivor 空间的数据 —— 此处列出的不多。
|
Geronimo 和初始构建
在您前面下载的二进制和源安装中有几个目录。二进制下载包括运行和使用 Geronimo 所必需的 Geronimo 的梗概。源下载包括所有 Geronimo 源代码,包括用于构建整棵树的 Maven 构建脚本。首先来看二进制发行版,然后再看源代码发行版。
关于 Geronimo 示例应用程序的 JVM 统计信息
Geronimo 附带了几个示例 Web 应用程序。既然您有了一些从 JVM 提取 JVM 统计信息的工具,就可以容易地为 Geronimo 应用程序执行此操作。
启动 Geronimo
仅仅启动 Geronimo 并用 visualgc
监视它就相当有趣,如 图 4、图 5 和 图 6 所示。
用标准的 java -jar %GERONIMO_HOME%/bin/server.jar
命令启动 Geronimo。仅通过使用启动命令上的 -server
选项即可获得直接视图,如 图 7 所示。
注意,JIT 编译少得多。这是因为在您使用 -server
选项启动 JVM 时加载了更多的类。默认的启动模式设计用于更快的启动,以适应桌面应用程序。
在这两种情况下,您都会在堆上看到许多长时间运行的对象,但是一旦 Geronimo 完全启动,这个数量将趋于平缓。这展示所有正在被加载的服务器对象,如各种 GBeans 以及它们管理的服务。Geronimo 开发人员将因看不到内存泄漏的迹象而高兴,因为老的一代和永久的一代分配趋于平缓。
示例 Web 应用程序
现在您也可以运行一些包含的 Geronimo Web 应用程序。图 8 中的图形展示 JSPX-XHTML 示例应用程序的垃圾收集动作。
您可以看到左侧的对象突然增多,然后大部分对象将在呈现该页面后消失,这与您所期望的一样。您可以看到也对应于应用程序运行的 JIT 编译和类加载事件。
既然了解了如何访问和分析运行 Geronimo 的某个示例 Web 应用程序时生成的 JVM 统计信息,就可以开始分析自己的应用程序了。大概就是启动 Geronimo、启动 visualgc
,然后部署和/或启动您的应用程序。对它运行一些事件,观察它加载类、编译字节代码以及管理内存。
|
结束语
JVM 统计信息在调优应用程序时非常宝贵。Sun 提供的工具让您快速分析应用程序、执行优化并查看优化的效果。它们还允许试验多个 JVM 选项,以对应用程序执行附加调整。Geronimo 的目标之一是提供高性能应用服务器,而 JVM 统计信息的分析是寻求最高应用程序性能的一项重要补充。