使用JRockit Mission Control进行性能分析和调优


Mission ControlBEA JRockit JVM自带的一组以极低的开销来监控、管理和分析生产环境中的应用程序的工具。它包括三个独立的应用程序:内存泄漏监测器(Memory Leak Detector)、JVM运行时分析器(Runtime Analyzer)和管理控制台(Management Console)。BEAJRockit R26版本就开始捆绑这个工具套件,目前最新的版本是3.0。最近我们使用其中的Runtime Analyzer对国内某著名行业解决方案进行性分析和调优。


 


JRockit Runtime AnalyzerJRA)是一个JVM分析器,是一个随需应变的“动态记录器”。它记录了Java应用程序和JVM在一段预定的时间内的详细记录。然后通过JRA应用程序对记录下来的文件进行离线分析。所记录的数据包括对方法的调用跟踪、错误的同步、锁定的分析,还有垃圾收集统计信息,优化决策以及对象统计信息和其他重要的应用程序/JVM行为。它的目的是让JRockit开发人员能够找到良好的方法来基于现实应用程序优化JVM,对于帮助客户在生产和开发环境中解决问题十分有用。


 


2.性能数据分析和调优


 


在本次项目中,操作|A和操作B的百人并发脚本执行完成的时间接近两分钟,因此我们使用JRA进行了2分钟(120)的记录。在GC常规信息中,我们发现在短短两分钟时间内,垃圾收集的总数高达365次,而由此造成的暂停时间有42.5秒之多。也就是说35%的执行时间是在做垃圾收集。


 


因为最大堆尺寸已经设置成1024M,对于32位操作系统上的Java应用已经是足够大了(在IA32构架下,由于操作系统给每个进程的最大内存寻址空间为1.8G,因此最大堆尺寸不能超过1.8G),因此堆的大小并不是造成频繁垃圾收集的原因。那么在高并发度的场景下,可能的影响因素很可能是Nursery大小。


 


Nursery 也称为新代,是指运行分代式垃圾收集器时,在堆中分配 新对象 的可用块区域。 Nursery 变满时,会在新垃圾收集中单独对其进行垃圾收集。Nursery 大小决定了新收集的频率和持续时间。较大 Nursery 会降低收集的频率,但是会稍微增加每个新收集的持续时间。 Nursery 之所以具有价值,是因为 Java 应用程序中的大多数对象都是在新代中夭亡的。与收集整个堆相比,应首选从新空间中收集垃圾,因为该收集过程的开销更低,而且在触发收集时,新空间中的大多数对象均已死亡。在新收集过程中,JVM 首先确定 Nursery 中的哪些对象是活动的,此后将它们提升到旧空间,并释放 Nursery,供分配新的小对象使用


 


Nursery的默认缺省值是10M/CPU,对于我们Clovertown服务器来说,只有20M。由于出现频繁收集的情况,那么我们推断是由于Nursery的默认值太低的原因。一方面在高并发用户的场景下,肯定是有大量的新对象产生,那么Nursery的空闲空间很容易就被耗尽。因此Nursery发生垃圾收集频率就会比较高。另一方面更短的垃圾收集间隔会使得新对象在Nursery的存活率提高因为很多新对象可能还没来得及使用完毕就已经发生垃圾收集。这样更多的对象会被提升到旧代,使得旧代的对象也会急剧增加,从而使得旧代发生垃圾收集的频率也增加。


 


因为JRockit JVM可以使用-Xns:<size>来设置Nursery的尺寸,我们要在保证垃圾回收停顿时间(garbage collection-pause)尽可能短的同时,尽量加大Nursery的尺寸,这在创建了大量的临时对象时尤其重要。推荐值是最大堆尺寸的10%,因此我们在JRockit的运行时参数上添加了 –Xns100m。再次运行脚本后,JRA收集的信息显示GC暂停时间骤降到15.3s,次数也有所减少,降到296


 




















Nursery大小


20M(默认值)


100M


GC暂停时间


42.5s


15.3s


垃圾收集的总数


365


296


平均暂停时间


116ms


52ms


 


此外,我们从方法信息中可以看到调用次数最多耗时间最长的两个方法分别是jrockit.vm.Locks.monitorEnterSecondStagecom.ABC.StateManager.makeState两个方法。展开前置任务后发现调用这两个方法最多的方法是com.ABC.SqlQueryAction.query。而jrockit.vm.Locks.monitorEnterSecondStage显然是JRockit实现锁机制的特定的API。因此我们怀疑是对数据库的操作时有资源互斥的现象发现。


 


考虑到高并发用户的场景下,对数据库操作的并发度也很高,因此对数据库连接的争用比较激烈。我们察看了一下当时WebLogic JDBC的配置,发现connection pool的大小只是缺省值20,相对来说偏小了,对性能会有一定的影响。因此我们增大connection pool的大小到100。重新运行测试脚本后发现性能有较大提升。


 


 



















 


JDBC connection size 20  w/ default nursery


JDBC connection size 100 w/ 100M nursery


Increase %


 


操作A


22.125


12.079


83%


操作B


35.195


21.773


62%


 


 


在性能调优完成后,我们又进行了功能测试(回归测试),以验证上述改动没有影响系统的功能性正确。


四、小结


其实利用Mission ControlJava应用进行调优并不难,对吧?希望本次性能分析调优的过程可以给大家一些启发,今后可以应用到日常工作中。

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.