版权声明:原创作品,允许转载,转载时请务必以超链接形式标明文章
原始出处 、作者信息和本声明。否则将追究法律责任。
http://intelisn.blog.51cto.com/626310/130730
Mission Control
是
BEA JRockit JVM
自带的一组以极低的开销来监控、管理和分析生产环境中的应用程序的工具。它包括三个独立的应用程序:内存泄漏监测器(
Memory Leak Detector
)、
JVM
运行时分析器(
Runtime Analyzer
)和管理控制台(
Management Console
)。
BEA
从
JRockit R26
版本就开始捆绑这个工具套件,目前最新的版本是
3.0
。最近我们使用其中的
Runtime Analyzer
对国内某著名行业解决方案进行性分析和调优。
JRockit Runtime Analyzer
(
JRA
)是一个
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.monitorEnterSecondStage
和
com.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 Control
对
Java
应用进行调优并不难,对吧?希望本次性能分析调优的过程可以给大家一些启发,今后可以应用到日常工作中。
本文出自 “Intel_ISN” 博客,请务必保留此出处http://intelisn.blog.51cto.com/626310/130730