JVM(和Spark)性能优化:使用Java Mission Control (6)
3.2.3 线程(活跃度、时延、响应性、死锁)
线程相关的问题比较棘手,词汇也较多,例如卡住stuck、停滞stall、挂起hang/ suspend 等生活用语,还有正式术语:停放park(IBM网站的翻译)、等待wait、阻塞block等。而今天的Java应用程序通常是很大规模的,7*24小时运行于数十个CPU核上,线程数量常常高达32~128个,需要可视化的工具才能更好地分析热点线程、争用、等待时间、锁等情况。
要了解哪些资源拥有处于停放 (park)、等待或阻塞状态的线程,还可能指示哪个线程拥有该资源。争用选项卡包含有关锁、受阻线程和阻塞线程的信息。当存在性能问题但 CPU 负载不高时,某些线程可能被阻止。此选项卡对分析线程阻止问题和查找锁过多的根源非常有用。等待时间选项卡包含有关导致线程不执行 Java 代码 (线程停滞) 的事件的信息。可以查看线程休眠、等待、受阻等等所花费的时间。
争用选项卡:显示出在5个类上争用锁最激烈,跟业务有关的主要在kryo上
com.esotericsoftware.kryo.io.Output.
显示业务侧的序列化/反序列化很阻塞线程前进:
![](http://simg.hwclouds.com/upload/files/jpg/20161116/20161116170338_15784.jpg)
等待时间选项卡:也显示出业务侧的序列化/反序列化类在使用Kryo上有较多次数和时间的阻塞:
![](http://simg.hwclouds.com/upload/files/jpg/20161116/20161116170411_43278.jpg)
线程转储选项卡:可代替Jstack,默认1分钟转储一次:
![](http://simg.hwclouds.com/upload/files/jpg/20161116/20161116170437_40847.jpg)
锁定实例选项卡:显示出业务侧的序列化/反序列化类上阻塞了数十个Spark的Executor task launch worker线程池上的线程:
![](http://simg.hwclouds.com/upload/files/jpg/20161116/20161116170503_17126.jpg)
这些线程竟争的热点,常常跟内存压力极大的类有关,我们从内存->分配->新TLAB的分配->按类分配 中也可以发现相关性:
![](http://simg.hwclouds.com/upload/files/jpg/20161116/20161116170528_21800.jpg)
把业务侧的序列化/反序列化类优化,例如用KryoPool /KryoFactory 替换Kryo的ThreadLocal写法等,再度量,显示出没有出现以上大量阻塞线程的情况了:
![](http://simg.hwclouds.com/upload/files/jpg/20161116/20161116170556_12909.jpg)
活跃度、时延、响应性
如果大量的线程停滞、阻塞、等待,说明线程的活跃度降低了,则会增加应用程序的时延、降低响应性。可能通过事件->图形,查看占统治的是什么类型?导致锁定的类是什么?哪儿的代码导致了事件发生?找到原因后尝试修复(例如是否滥用了同步),再对比,是否处于运行的线程更多或少了?是否有更好的活跃度?还有多少线程停滞?
事件|堆栈跟踪|堆栈跟踪树,点击 表头的总计排序,可以看到造成时延的数据分布,哪些最导致了时延。
![](http://simg.hwclouds.com/upload/files/jpg/20161116/20161116170633_23000.png)
死锁
最糟糕的活跃度是死锁。通过JMC中的JMV浏览器|MBean服务器|运行时|线程,勾选死锁检测,点击表格中的死锁列排序,让死锁的线程排到上面。可以查看到死锁的线程名,在哪个方法里的哪行代码死锁了?
![](http://simg.hwclouds.com/upload/files/jpg/20161116/20161116170659_84413.png)
- 点赞
- 收藏
- 关注作者
评论(0)