作者 | 小白一隻
【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:
然後啟動 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 等技術領域、聚焦雲原生流行技術趨勢、雲原生大規模的落地實踐,做最懂雲原生開發者的公眾號。”