本文摘自《Java性能优化权威指南》第6章“Java应用性能分析技巧”,这一章介绍了一些非常实用的应用性能分析技巧。本文节选的是正文里穿插的一个小TIP。


Performance Analyzer中标记为JVM-System条目代表JVM内部消耗的时间。查看锁竞争信息时,该条目代表消耗在JVM内部锁上的时间或时间百分比。图6-11中JVM-System所消耗的时间值有些大得出奇。

enter image description here

图6-11 按独占指标排序的Java monitor对象/锁持有时间

针对这一现象,我们会进一步解释,逐步澄清大家心中的谜团。第5章曾经提到数据呈现格式的切换,无论是从用户模式切换到专家模式或是机器模式,都会暴露(显示)JVM内部的操作并统计到用户模式下的JVM-System条目中。同样要注意的是,切换到专家模式或机器模式时,Java monitor对象会以_lwp_mutex__lwp_cond_wait__lwp_park的条目显示较高的竞争。图6-13显示了同样的性能数据,不过这次在Performance Analyzer中是从用户模式切换到专家模式。

enter image description here

图6-13 用户模式切换到专家模式

比较图6-11和图6-13表明JVM-System条目划分为__lwp_condition_wait__lwp_park操作。__lwp_condition_wait__lwp_park之和与图6-11中的JVM-System基本相等。看到这个结果,你的第一印象可能是JVM内部也存在锁竞争。但选择__lwp_cond_wait条目,之后选择“Callers-Callees”选项卡,沿着调用栈分析,最后会发现锁活动的源头是__lwp_cond_wait,换句话说,这些锁活动都与JVM-System条目有关,如图6-14所示。

图6-14中显示的5个方法都为JVM的内部方法。我们注意到超过95%的归因锁时间消耗在GCTaskManager::get_task(unsigned)方法上。

enter image description here

图6-14 逆溯__lwp_cond_wait的调用函数栈

这个方法是Java HotSpot虚拟机垃圾收集子系统的一部分。垃圾收集器子系统工作时,会阻塞等待在一个工作队列中。图6-14列出的方法代表了Java HotSpot虚拟机可能阻塞等待的各个工作队列。例如,VMThread::loop()方法代表Java HotSpot虚拟机阻塞在一个队列中等待接受工作。你可以将VMThread想像成Java HotSpot虚拟机的“内核线程”。CompilerBroker::compile_thread_loop()方法代表JIT编译子系统阻塞等待另一个队列,诸如此类。了解了这些之后,你应该可以接受为什么我们要忽略用户模式下JVM-System条目下的内容,不将其统计在热点锁竞争的范围之内的原因了。

《Java性能优化权威指南》的边边角(3)——生存代和内存泄漏