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