Java 虚拟机诊断利器
作者 | 小白一只
【Arthas 官方社區正在舉行征文活動,參加即有獎品拿~點擊投稿】
背景
最近學習Java字節碼過程中遇到了反射,有段代碼是這樣的:
package com.example.classstudy;import java.lang.reflect.Method;/*** @author TY*/ public class ReflectionTest {private static int count = 0;public static void foo() {new Exception("test#" + (count++)).printStackTrace();}public static void main(String[] args) throws Exception {Class<?> clz = Class.forName("com.example.classstudy.ReflectionTest");Method method = clz.getMethod("foo");for (int i = 0; i < 20; i++) {method.invoke(null);}} }就是一段簡單的反射調用 foo 方法,執行 20 次,然后看執行結果:
可以看到在 15 次調用 foo 方法后,第 16 次調用 foo 方法是走的 GeneratedMethodAccessor1 來調用的。我嘞個擦,怎么回事,調著調著就不一樣了,于是跟代碼,跟到了下面這個類:
其中這句代碼就是對反射調用的次數做了控制
if (++this.numInvocations > ReflectionFactory.inflationThreshold() && !ReflectUtil.isVMAnonymousClass( this.method.getDeclaringClass())) {MethodAccessorImpl var3 = (MethodAccessorImpl)(new MethodAccessorGenerator()).generateMethod(this.method.getDeclaringClass(), this.method.getName(), this.method.getParameterTypes(), this.method.getReturnType(), this.method.getExceptionTypes(), this.method.getModifiers());this.parent.setDelegate(var3);}this.numInvocations 的默認值是 0,而 ReflectionFactory.inflationThreshold() 默認是 15,當大于 15 的時候會通過 ASM 技術動態生成 GeneratedMethodAccessor1 類來調用 invoke 方法,但是,因為是動態生成的,我們怎么才能看到這個類實際長什么樣子呢?
Arthas
這個時候,就可以用上阿里的 arthas(阿爾薩斯)了。
首先下載 arthas:
curl?-O?https://alibaba.github.io/arthas/arthas-boot.jar
然后啟動 arthas:
java?-jar?arthas-boot.jar
啟動之后界面長這個樣子:
其中什么 23012, 28436 等是當前環境中現有的 java 進程,然后需要連接到哪個進程就輸前面的編號(1234 啥的),輸了之后回車。那么我首先改寫一下最開始的那個程序,讓他不退出:
package com.example.classstudy;import java.lang.reflect.Method;/*** @author TY*/ public class ReflectionTest {private static int count = 0;public static void foo() {new Exception("test#" + (count++)).printStackTrace();}public static void main(String[] args) throws Exception {Class<?> clz = Class.forName("com.example.classstudy.ReflectionTest");Method method = clz.getMethod("foo");for (int i = 0; i < 20; i++) {method.invoke(null);}System.in.read();} }重新啟動程序之后,查看 arthas 界面:
可以看到 32480 正是我們運行的程序,輸入編號 2 去連接到該進程:
然后就可以將動態生成的類 dump 下來:
dump?sun.reflect.GeneratedMethodAccessor1
可以看到字節碼被 dump 下來了,找到該文件用 javap 來查看:
javap?-c?-v?-p?-l?GeneratedMethodAccessor1.class
沒有問題,可以查看到,然后剩下的就是人肉翻譯字節碼啦。。。
本篇關于Arthas的使用其實很少,我只是因為學到這個地方簡單的用了下,但是已經感受到了 Arthas 的強大之處,它甚至還支持 web 界面。。。
相當厲害!
Arthas 征文活動火熱進行中
Arthas 官方正在舉行征文活動,如果你有:
- 使用 Arthas 排查過的問題
- 對 Arthas 進行源碼解讀
- 對 Arthas 提出建議
- 不限,其它與 Arthas 有關的內容
歡迎參加征文活動,還有獎品拿哦~點擊投稿
“阿里巴巴云原生關注微服務、Serverless、容器、Service Mesh 等技術領域、聚焦云原生流行技術趨勢、云原生大規模的落地實踐,做最懂云原生開發者的公眾號。”
總結
以上是生活随笔為你收集整理的Java 虚拟机诊断利器的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 是谁在调用我?使用 arthas+jpr
- 下一篇: 开放下载 | 和 4000+Java 开