Alibaba开源的Arthas是一个非常有名的Java诊断工具,他可以解析JVM的运行资源占用,运行状况,可以查看类的加载过程,使用的类加载器等等。但是比较可惜的是,他没有对于OpenJ9做出额外的支持,因此当你的JVM选择OpenJ9后,使用arthas可能会存在一定问题。本文将从我的亲身使用出发,看看OpenJ9在使用Arthas时会遇到哪些问题?
dashboard
dashboard是arthas的指令之一,该指令用于展示当前系统的实时面板。但是在实际使用中会发现,如果OpenJ9中启用-Xgcpolicy:balanced的gc策略,会报如下的错误:
[arthas@73192]$ dashboard
process dashboard failed: init argument cannot be less than -1
查看Arthas的日志文件,文件中有更加详细的日志:
java.lang.IllegalArgumentException: init argument cannot be less than -1
at java.lang.management.MemoryUsage.<init>(MemoryUsage.java:94)
at com.ibm.java.lang.management.internal.MemoryPoolMXBeanImpl.getUsageImpl(Native Method)
at com.ibm.java.lang.management.internal.MemoryPoolMXBeanImpl.getUsage(MemoryPoolMXBeanImpl.java:235)
at com.taobao.arthas.core.command.monitor200.MemoryCommand.getUsage(MemoryCommand.java:82)
at com.taobao.arthas.core.command.monitor200.MemoryCommand.memoryInfo(MemoryCommand.java:52)
at com.taobao.arthas.core.command.monitor200.DashboardCommand$DashboardTimerTask.run(DashboardCommand.java:245)
at java.util.TimerThread.mainLoop(Timer.java:555)
at java.util.TimerThread.run(Timer.java:505)
本来以为是Arthas对于OpenJ9不兼容导致的,但是经过一番研究发现事情并不是那么简单。
写一个最简单的程序来进行验证:
public static void main(String[] args) {
List<MemoryPoolMXBean> memoryPoolMXBeans = ManagementFactory.getMemoryPoolMXBeans();
for (MemoryPoolMXBean memoryPoolMXBean : memoryPoolMXBeans) {
memoryPoolMXBean.getUsage();
}
}
这么简单一个demo居然在OpenJ9 balanced gc策略下抛出了异常:
Exception in thread "main" java.lang.IllegalArgumentException: init argument cannot be less than -1
at java.management/java.lang.management.MemoryUsage.<init>(MemoryUsage.java:94)
at java.management/com.ibm.java.lang.management.internal.MemoryPoolMXBeanImpl.getUsageImpl(Native Method)
at java.management/com.ibm.java.lang.management.internal.MemoryPoolMXBeanImpl.getUsage(MemoryPoolMXBeanImpl.java:235)
at org.example.openj9.Test.main(Test.java:12)
经过测试验证,确认了这个是OpenJ9的bug,错怪Arthas了!
经过和OpenJ9社区的沟通,发现这个bug会在空闲的region
数小于Eden region
数时产生,此时的"reserved size"会小于0,并导致报错。遗憾的是,此bug目前还未修复,预计将在后续的7月份的版本中进行修复并发布。
trace
使用trace可以排查具体的类的加载时长,排查执行慢的原因。不过在OpenJ9场景下使用trace会出现如下报错:
[arthas@22508]$ trace org.springframework* * '#cost > 1000'
Affect(class count: 4180 , method count: 33388) cost in 28438 ms, listenerId: 1
Enhance error! exception: java.lang.VerifyError
error happens when enhancing class: null, check arthas log: /Users/logs/arthas/arthas.log
查看日志发现如下报错:
java.lang.VerifyError: null
at sun.instrument.InstrumentationImpl.retransformClasses0(Native Method)
at sun.instrument.InstrumentationImpl.retransformClasses(InstrumentationImpl.java:156)
at com.taobao.arthas.core.advisor.Enhancer.enhance(Enhancer.java:446)
at com.taobao.arthas.core.command.monitor200.EnhancerCommand.enhance(EnhancerCommand.java:162)
at com.taobao.arthas.core.command.monitor200.EnhancerCommand.process(EnhancerCommand.java:109)
at com.taobao.arthas.core.shell.command.impl.AnnotatedCommandImpl.process(AnnotatedCommandImpl.java:82)
at com.taobao.arthas.core.shell.command.impl.AnnotatedCommandImpl.access$100(AnnotatedCommandImpl.java:18)
at com.taobao.arthas.core.shell.command.impl.AnnotatedCommandImpl$ProcessHandler.handle(AnnotatedCommandImpl.java:111)
at com.taobao.arthas.core.shell.command.impl.AnnotatedCommandImpl$ProcessHandler.handle(AnnotatedCommandImpl.java:108)
at com.taobao.arthas.core.shell.system.impl.ProcessImpl$CommandProcessTask.run(ProcessImpl.java:385)
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$201(ScheduledThreadPoolExecutor.java:180)
at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:293)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
at java.lang.Thread.run(Thread.java:826)
这让我百思不得其解,没办法只好求助Arthas社区,可是得到的结果就是Arthas不支持OpenJ9。没办法,既然不支持,那么我们就换种办法来排查问题。
火焰图
Arthas火焰图是基于开源项目async-profiler
实现的,async-profiler
使用C++实现。支持生成应用热点的火焰图。其也可以用于排查应用执行慢的问题。他本质上是通过不断的采样,然后把收集到的采样结果生成火焰图。
然而在实际的使用中,会发现火焰图也不支持OpenJ9。
没办法,又又又只能去社区寻找答案。最终经过排查,发现async-profiler
是做了OpenJ9的支持的,不过,这些支持在2.7+版本后才陆续合并入主分支,而Arthas的最新版本引用的是2.6.x的async-profiler
,因此不支持OpenJ9也是情理之中了。
于是我们只好自己动手丰衣足食。好在Arthas集成async-profiler
的方法非常粗暴,是直接使用的so文件,于是我们直接替换Arthas的async-profiler
目录下的几个so文件,将之替换为最新版本的,果然火焰图能力就能够正常使用了。
后续在提了Issue之后,Arthas社区近期反应已经将async-profiler
升级至了高版本,因此只要下载最新版本就能让OpenJ9也可以使用Arthas的火焰图能力了。
总结
OpenJ9
虽然有其优势,但是在实际中的用户远远不如HotSpot
,因此在各个开源项目中的支持还远远不够。在折腾Arthas的过程中遇到了无数的坑,而且很多还是无法简单解决的,本文只是简单选取几个遇到的典型问题,希望能够有相同需求的朋友们能够一起来 踩坑 探索。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。