We read every piece of feedback, and take your input very seriously.
To see all available qualifiers, see our documentation.
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Arthas是阿里巴巴开源的Java应用诊断利器,本文介绍Arthas 3.1.1版本里jad命令的实现原理。
jad
jad即java decompiler,把JVM已加载类的字节码反编译成Java代码。比如反编译String类:
String
$ jad java.lang.String ClassLoader: Location: /* * Decompiled with CFR . */ package java.lang; import java.io.ObjectStreamField; ... public final class String implements Serializable, Comparable<String>, CharSequence { private final char[] value; private int hash; private static final long serialVersionUID = -6849794470754667710L; private static final ObjectStreamField[] serialPersistentFields = new ObjectStreamField[0]; public static final Comparator<String> CASE_INSENSITIVE_ORDER = new CaseInsensitiveComparator(); public String(byte[] arrby, int n, int n2) { String.checkBounds(arrby, n, n2); this.value = StringCoding.decode(arrby, n, n2); } ...
反编译有两部分工作:
那么怎么从运行的JVM里获取到字节码?
最常见的思路是,在classpaths下面查找,比如 ClassLoader.getResource("java/lang/String.class"),但是这样子查找到的字节码不一定对。比如可能有多个冲突的jar,或者有Java Agent修改了字节码。
classpaths
ClassLoader.getResource("java/lang/String.class")
从JDK 1.5起,有一套ClassFileTransformer的机制,Java Agent通过Instrumentation注册ClassFileTransformer,那么在类加载或者retransform时就可以回调修改字节码。
ClassFileTransformer
Instrumentation
retransform
显然,在Arthas里,要增强的类是已经被加载的,所以它们的字节码都是在retransform时被修改的。 通过显式调用Instrumentation.retransformClasses(Class<?>...)可以触发回调。
Instrumentation.retransformClasses(Class<?>...)
Arthas里增强字节码的watch/trace/stack/tt等命令都是通过ClassFileTransformer来实现的。
watch
trace
stack
tt
ClassFileTransformer的接口如下:
public interface ClassFileTransformer { byte[] transform( ClassLoader loader, String className, Class<?> classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws IllegalClassFormatException;
看到这里,读者应该猜到jad是怎么获取到字节码的了:
Instrumentation.retransformClasses
transform
获取到字节码之后,怎样转换为Java代码呢?
以前大家使用比较多的反编译软件可能是jd-gui,但是它不支持JDK8的lambda语法和一些新版本JDK的特性。
jd-gui
后面比较成熟的反编译软件是cfr,它以前是不开源的。直到最近的0.145版本,作者终于开源了,可喜可贺。地址是
cfr
0.145
在Arthas jad命令里,通过调用cfr来完成反编译。
99%的情况下,jad命令dump下来的字节码是准确的,除了一些极端情况。
retransformClasses
所以目前在Arthas里,如果开两个窗口,一个窗口执行watch/tt等命令,另一个窗口对这个类执行jad,那么可以观察到watch/tt停止了输出,实际上是因为字节码在触发了retransformClasses之后,watch/tt所做的修改丢失了。
如果想精确获取到JVM内运行的Java字节码,可以使用这个dumpclass工具,它是通过sa-jdi.jar来实现的,保证dump下来的字节码是JVM内所运行的。
dumpclass
sa-jdi.jar
总结jad命令的工作原理:
jad命令可以在线上快速检查运行时的代码,并且结合mc/redefine命令可以热更新代码:
mc
redefine
原文链接:https://mp.weixin.qq.com/s/rK3qR6vpbr83dRThfLutsg
The text was updated successfully, but these errors were encountered:
还可以通过JDK自带的工具来查询/dump class:jhsdb hsdb
Sorry, something went wrong.
真不错 o( ̄▽ ̄)d
No branches or pull requests
Arthas是阿里巴巴开源的Java应用诊断利器,本文介绍Arthas 3.1.1版本里
jad
命令的实现原理。jad
命令介绍jad即java decompiler,把JVM已加载类的字节码反编译成Java代码。比如反编译
String
类:获取到类的字节码
反编译有两部分工作:
那么怎么从运行的JVM里获取到字节码?
最常见的思路是,在
classpaths
下面查找,比如ClassLoader.getResource("java/lang/String.class")
,但是这样子查找到的字节码不一定对。比如可能有多个冲突的jar,或者有Java Agent修改了字节码。ClassFileTransformer机制
从JDK 1.5起,有一套
ClassFileTransformer
的机制,Java Agent通过Instrumentation
注册ClassFileTransformer
,那么在类加载或者retransform
时就可以回调修改字节码。显然,在Arthas里,要增强的类是已经被加载的,所以它们的字节码都是在
retransform
时被修改的。通过显式调用
Instrumentation.retransformClasses(Class<?>...)
可以触发回调。Arthas里增强字节码的
watch
/trace
/stack
/tt
等命令都是通过ClassFileTransformer
来实现的。ClassFileTransformer
的接口如下:看到这里,读者应该猜到
jad
是怎么获取到字节码的了:ClassFileTransformer
Instrumentation.retransformClasses
触发回调transform
函数里获取到字节码ClassFileTransformer
使用cfr来反编译
获取到字节码之后,怎样转换为Java代码呢?
以前大家使用比较多的反编译软件可能是
jd-gui
,但是它不支持JDK8的lambda语法和一些新版本JDK的特性。后面比较成熟的反编译软件是
cfr
,它以前是不开源的。直到最近的0.145
版本,作者终于开源了,可喜可贺。地址是在Arthas
jad
命令里,通过调用cfr
来完成反编译。jad
命令的缺陷99%的情况下,
jad
命令dump下来的字节码是准确的,除了一些极端情况。ClassFileTransformer
可能有多个,那么在JVM里运行的字节码里,可能是被多个ClassFileTransformer
处理过的。retransformClasses
之后,这些注册的ClassFileTransformer
会被依次回,上一个处理的字节码传递到下一个。所以不能保证这些
ClassFileTransformer
第二次执行会返回同样的结果。ClassFileTransformer
会被删掉,触发retransformClasses
之后,之前的一些修改就会丢失掉。所以目前在Arthas里,如果开两个窗口,一个窗口执行
watch
/tt
等命令,另一个窗口对这个类执行jad
,那么可以观察到watch
/tt
停止了输出,实际上是因为字节码在触发了retransformClasses
之后,watch
/tt
所做的修改丢失了。精确获取JVM内运行的java字节码的办法
如果想精确获取到JVM内运行的Java字节码,可以使用这个
dumpclass
工具,它是通过sa-jdi.jar
来实现的,保证dump下来的字节码是JVM内所运行的。总结
总结
jad
命令的工作原理:ClassFileTransformer
,再触发retransformClasses
来获取字节码cfr
来反编译ClassFileTransformer
的方式来获取字节码有一定缺陷dumpclass
工具可以精确获取字节码jad
命令可以在线上快速检查运行时的代码,并且结合mc
/redefine
命令可以热更新代码:链接
原文链接:https://mp.weixin.qq.com/s/rK3qR6vpbr83dRThfLutsg
The text was updated successfully, but these errors were encountered: