写点什么

如何在 OpenJ9 场景下使用 Arthas

作者:骑牛上青山
  • 2023-05-14
    上海
  • 本文字数:2900 字

    阅读完需:约 10 分钟

Alibaba 开源的 Arthas 是一个非常有名的 Java 诊断工具,他可以解析 JVM 的运行资源占用,运行状况,可以查看类的加载过程,使用的类加载器等等。但是比较可惜的是,他没有对于 OpenJ9 做出额外的支持,因此当你的 JVM 选择 OpenJ9 后,使用 arthas 可能会存在一定问题。本文将从我的亲身使用出发,看看 OpenJ9 在使用 Arthas 时会遇到哪些问题?




dashboard

dashboard 是 arthas 的指令之一,该指令用于展示当前系统的实时面板。但是在实际使用中会发现,如果 OpenJ9 中启用-Xgcpolicy:balanced 的 gc 策略,会报如下的错误:


[arthas@73192]$ dashboardprocess 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: 1Enhance error! exception: java.lang.VerifyErrorerror 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 的过程中遇到了无数的坑,而且很多还是无法简单解决的,本文只是简单选取几个遇到的典型问题,希望能够有相同需求的朋友们能够一起来踩坑探索。


发布于: 刚刚阅读数: 2
用户头像

还未添加个人签名 2021-05-18 加入

还未添加个人简介

评论

发布
暂无评论
如何在OpenJ9场景下使用Arthas_Java_骑牛上青山_InfoQ写作社区