内容简介:Arthas是阿里巴巴开源的Java应用诊断利器,本文介绍Arthas 3.1.1版本里jad即java decompiler,把JVM已加载类的字节码反编译成Java代码。比如反编译反编译有两部分工作:
Arthas是阿里巴巴开源的 Java 应用诊断利器,本文介绍Arthas 3.1.1版本里 jad
命令的实现原理。
jad
命令介绍
jad即java decompiler,把JVM已加载类的字节码反编译成Java代码。比如反编译 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); } ...
获取到类的字节码
反编译有两部分工作:
- 获取到字节码
- 反编译为Java代码
那么怎么从运行的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
的接口如下:
public interface ClassFileTransformer { byte[] transform( ClassLoader loader, String className, Class<?> classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws IllegalClassFormatException;
看到这里,读者应该猜到 jad
是怎么获取到字节码的了:
ClassFileTransformer Instrumentation.retransformClasses transform ClassFileTransformer
使用cfr来反编译
获取到字节码之后,怎样转换为Java代码呢?
以前大家使用比较多的反编译软件可能是 jd-gui
,但是它不支持JDK8的lambda语法和一些新版本JDK的特性。
后面比较成熟的反编译软件是 cfr
,它以前是不开源的。直到最近的 0.145
版本,作者终于开源了,可喜可贺。地址是
在Arthas jad
命令里,通过调用 cfr
来完成反编译。
jad
命令的缺陷
99%的情况下, jad
命令dump下来的字节码是准确的,除了一些极端情况。
-
因为JVM里注册的
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
命令可以热更新代码:
- jad/mc/redefine线上热更新一条龙: http://hengyunabc.github.io/arthas-online-hotswap/
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网
猜你喜欢:- Golang源码探索(一) 编译和调试源码
- 写Java这么久,JDK源码编译过没?编译JDK源码踩坑纪实 原 荐
- JVM源码分析-JVM源码编译与调试
- 使用源码编译Hadoop
- Runtime源码编译
- 下载编译AOSP源码
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。