开发者学堂课程【线上问题排查利器 Alibaba Arthas(上):class 和 classloader 相关命令:jad 和 mc】学习笔记,与课程紧密连接,让用户快速学习知识。
课程地址:https://developer.aliyun.com/learning/course/746/detail/13195
class 和 classloader 相关命令:jad 和 mc
内容介绍
一、简介
二、jad
三、mc
一、简介
class/classloader (类/类加载器)相关的第二组命令,分成三个命令。
1.jad:把字节码文件反编译成源代码
2.mc:在内存中把源代码编译成字节码文件,和jad命令的功能相反
3.redefine:把新生成的字节码文件在内存中执行
上述三个命令放在一起,可以形成一个组合,第一步Jad,第二步是mc,第三步是redefine.
作用:可以在程序实际运行过程中,对某一个类进行反编译,甚至可以进行修改,然后作用到实际的运行环境中。
二、jad
1.jad 作用
反编译指定已加载类源码(得到源码)
(1)Jad 命令将 JVM 虚拟机中实际运行的 class(类)的 byte code(字节码文件) 反编译成 java 代码
作用:便于理解实际运行时的业务逻辑
(2)将反编译好的源代码arthas Console 的控制台上的输出,反编译出来的源码是带语法高亮,阅读更方便是非常人性化的设计;
(3)反编译出来的 java 代码可能会存在语法错误,但不影响进行阅读理解
2.jad参数说明
(1)class-pattern:类名表达式匹配,一般使用包名.类名的写法,也可以使用正则表达式,但通常使用类名表达式。
(2)[E]:开启正则表达式匹配,默认为通配符匹配
3.jad 反编译函数的反编译命令的作用
可观察到数学游戏一直在运行,并且了解到数学游戏的源码。
本次课不反编译数学游戏,可以反编译 java jdk 中的 String 函数。
(1)编译 java.lang.String 函数
jad java.lang.string,点击回车键
因为 string 函数中内容较多,所以显示的代码也比较长。
可看到 string 函数里的方法,反编译代码的可读性非常好。
包括:变量的命名,语法的高亮显示都比较方便进行阅读。
反编译出的类,不仅有源代码,还有其他的信息(可在最上方看)
ClassLoader: #显示类加载器
Location: #显示类所在的包
package java. Lang;
Lmport java .10. ObjectstreamField;
import java 1o. Serializable;
import java . io. UnsupportedEncodingException;
import java nio charset . Charset;
import java. util . ArrayList;
import java. util. Arrays B
Limport java . util . Comparator;
import java . util. Formatter ;
import java. util.List;
import java . util. Locale;
#显示源代码
但 string 类并没有显示
(2)反编译数学游戏
jad demo.MathGame,点击回车键
可观察到反编译出的内容中显示类加载器和所在包
ClassLoader:
+-sun.misc.Launcher$AppClassLoader@70dea4e
+-sun.misc.Launcher$ExtClassLoader@1b6d3586 #类加载器
Location ;
/root/.arthas/1ib/3.1.7/arthas/arthas-demo.jar #所在包
如果不想显示以上信息,只想显示源码,则可以添加 --source-only函数,该函数可以在反编绎时只显示源代码,方便和 mc /redefine 命令结合使用。
代码为jad demo.MathGame --source-only demo.MathGame,点击回车
此时反编译出的结果,只有源代码,没有类加载器 和所在包
(3)反编译指定函数;
例如: String 类反编译后代码过多,然而我们不想关注整个类,只想了解其中的一个方法,以 trim 方法为例,可以只反编译其中的一个方法,可直接在类名后跟方法名
代码为jad demo.MathGame trim,点击回车
可观察到此时只反编译出了 String 类的 trim 方法,便于只关注于某一个方法
三、mc
1.mc(Memory Compiler)作用
Memory Compiler/内存编译器,在内存里把正在运行的或者当前的 .java 程序编译成 .class,在 Arthas Console 内存里编译,
mc 和 javac 相似,javac 的作用是将 java 变为java.class文件
举例,无其他参数,直接指定源代码
2.mc命令的使用
(1)在 mc 中编译 Hello.java 文件为 Hello.class,该文件已经准备好 清除屏幕clear,点击回车键
Hello.java文件已经准备好,可用 cat Hello.java 命令看 Hello.java 文件的源码,输出代码后按回车键
从结果可了解到该类很简单,输出是 Hello World ,只有一个 main函数,从结果中可看出没有 clas s文件
输入 ls hello.* 命令可看出只有 Hello.java文 件
可用 javac 编译,在 Artha s里可通过 mc 进行编译,但必须要指定路径
原因:Arthas 的目录和所在的 Hello.java 文件的目录不同
Hello.java文件的目录在用户主目录(/root)下
所以可以选用绝对路径的方式写全代码
代码为 mc /root/Hello.java ,按回车键
结果显示了内存编译,输出到 root/.arthas/lib/3.1.7/arthas ,root/.arthas/lib/3.1.7/arthas是arthas安装目录,编译到 Hello.java 里
进入目录
cd .arthas/lib/3.1.7/artbas/,按回车键
ls,按回车键
发现结果中多出了 Hello.class 文件,将 Hello.class 生成文件的放到了root/.arthas/lib/3.1.7/arthas目录中
(2)通过 -d 命令指定输出目录
mc 起到了编译的作用,如果不想将 Hello.class 生成文件的放到了root/.arthas/lib/3.1.7/arthas 目录中,想放到 root 目录中,可以指定编译的目录
代码为mc /root/Hello.java -d /root,按回车键
发现此时输出为/root/Hello.class,证明Hello.class在/root目录下
回到用户主目录中观察
cd ,按回车键
ls,按回车键,可发现Hello.class文件
上述讲的是在内存中编译和反编译