class 和 classloader 相关命令:redefine | 学习笔记

简介: 快速学习 class 和 classloader 相关命令:redefine

开发者学堂课程【线上问题排查利器 Alibaba Arthas(上):class 和 classloader 相关命令:jad 和 mc】学习笔记,与课程紧密连接,让用户快速学习知识。

课程地址https://developer.aliyun.com/learning/course/746/detail/13196


class 和 classloader 相关命令:jad 和 mc


内容介绍

一、简介

二、redefine

三、总结


一、简介

class/classloader(类/类加载器)相关的第二组命令的三个命令。

redefine:把新生成的字节码文件在内存中执行。

重新定义,可以让反编译变成修改过的代码,让它重新在程序执行的时候起作用

二、redefine

1.redefine 作用

加载外部的 .class 文件,redefine 到 JVM 虚拟机里

该操作比较危险,所以应注意:

(1)redefine 后的原来的类不能恢复,redefine 有可能失败(不能新增新的成员变量和成员方法(不能加新的字段和新的方法),只能在现有的方法中修改代码,比如增加了新的field )

(2)reset 命令对 redefine 的类无效。如果想重置,需要 redefine 原始的字节码。

(3)redefine 命令和 jad (反编译)/ watch /trace /monitor/tt 等命令会冲突,执行完 redefine 之后,如果再执行上面提到的命令,则会把redefine的字节码重置,意味着修改后的无效,所以redefine命令应在jad(反编译)/watch/trace/monitor/tt 等命令之后执行。

注:watch /trace /monitor/tt 是未讲内容

2.redefine的限制

(1)不允许新增加 field/method

(2)正在跑的函数,没有退出(正在执行)不能生效,比如下面新增加的system.out.println,只有run() 函数里的会生效。

例:

public class MathGame {public static void main(String[] args) throws InterruptedException (

MathGame game = new MathGame() ;

while (true) {

game.run();

TimeUnit.SECONDS.sleep(1);

//这个不生效,因为代码一直跑在 while 里,死循环,无法进行修改,或修改后也无效

System.out.println("in loop");

}

}

public void run() throws InterruptedException {

//在 run() 中增加 System.out.println("call run( )") 生效,因为run() 函数每次都可以完整结束

System.out.println("call run( )");

try {

int number = random. nextInt();

List<Integer>primeFactors=primeFactors(number);

print(number,primeFactors);

}catch (Exception e) {

System.out.println(String.format("illegalArgumentCount:%3d,” illegalArgumentCount) +e.getMessage();

}

}

}

3.案例:结合 jad/mc 命令使用

cls:清除屏幕

(1)将数学游戏使用 jad 反编译 deno.MathGame

代码为 jad --source-only demo .MathGame ,回车

image.png

此步骤反编译到屏幕中,但需要反编译到文件中.使用jad 反编译 deno.MathGame 输出到/root/MathGame. Java,反编译时通过 --source-only 可只显示源码。

image.png代码为jad --source-only demo .MathGame > /root/MathGame. Java,回车

此时在屏幕上看不到结果

“>”为重定向,相当于把输出在默认的情况下,arthas 将源代码输出到屏幕上。但输出到屏幕上面不能进行编辑,所以“>”符号,将它重定向到另外的设备里。此时就可以把它输出的文件里,然后对它进行重新编写。

切换到 /root 目录下,输入 ls ,按回车键

可观察到多出 MathGame.Java 文件

image.png

在 vim 里对 MathGame.Java 文件进行编辑

代码为vim MathGame.Java ,按回车键

image.png可看出反编译的和源码有区别,源码 while (true){},反编译的为 do{} while (true);

在反编译的 main() 代码中加入 System.out.printIn (“在 main 函数中循环体内”);

代码如下:Public static vold main(String[] args) throws InterruptedException{

MathGame game = new MathGame();

do {

game.run();

TimeUnit.SECONDS.sleep(1L);

System.out.printIn(“在 main 函数中循环体内”);

//上行为加入代码,正常来说不起作用,因为该函数是正在执行的函数

} while (true);

}

在反编译的run()代码中加入System.out.printIn(“--  计算中的函数  --”);

代码如下:

public void run() throws InterruptedException {

try {

System.out.printIn(“ --  计算中的函数  --”);

//观察是否能输出“ --  计算中的函数  --”

int number = random.nextInt() / 10000;

Listc<Integer> primeFactors=this.primeFactors(nunber);

MathGame.print(number,primeFactors);

}

catch(Exception e) {System.out.println(String.format("llegalArgumentCount:%3d,”, this.illegalArgumentCount) + e.getMessage());

}

}

存盘退出;输入 wq 命令,按回车键

(2)按上面的代码编辑完毕以后,使用 mc 内存中对新的代码编译

-d:指定编译到 /root  路径中

编译 MathGame.java 文件

代码为mc /root/MathGame.java -d /root ,回车

image.png此时已经将其定义出,放到 demo/MathGame.Class 目录下

//代码应写全,必须要写绝对路径,否则会在 arthas 目录下找文件

在,则报错

image.png

(3)使用 redefine 命令加载新的字节码到内存里,使字节码起作用

demo/MathGame.Class :要加载的字节码文件

代码为redefine /root/ demo/MathGame.Class,回车

Redefine sucess 即为成功

image.png

发现在代码执行之前,结果上方实际上没有输出,直到“--计算中的函数--”此句话出现,此时是 redefine 后的代码起作用

image.png

以上讲的便是redefine的作用,三条命令讲述完毕。

便于在实际开发过程中被诊断的时候,在服务器实际运行过程中,想对代码进行调整或者修改来诊断错误,就可以进行如上操作。

输入代码 vim MathGame.java ,回车

注意:发现在编辑的过程中,System.out.printIn (“在 main 函数中循环体内”); 并没有显示

image.png

三、总结

类相关的命令:说明

Jad:反编译字节码文件得到 java 的源代码

Mc:在内存中将源代码编译成字节码

Redefine:将字节码文件重新加载到内存中执行

相关文章
|
6月前
|
前端开发 Java 程序员
ClassLoader如何加载class
ClassLoader如何加载class
55 0
|
21天前
|
Java 编译器 Maven
Java“class file contains wrong class”解决
当Java程序运行时出现“class file contains wrong class”错误,通常是因为类文件与预期的类名不匹配。解决方法包括:1. 确保类名和文件名一致;2. 清理并重新编译项目;3. 检查包声明是否正确。
|
1月前
|
Go Python
Classes & OOP--Defining Your Own Exception Classes
Classes & OOP--Defining Your Own Exception Classes
|
3月前
|
前端开发 Java 编译器
classpath中存在多个jar存在同限定名的class classloader会如何加载
总之,合理组织类路径和使用现代化的构建工具,可有效避免类加载冲突,保证应用的稳定运行。
128 8
|
6月前
|
Java
Class.forName和ClassLoader到底有啥区别
Class.forName和ClassLoader到底有啥区别
25 0
|
存储 安全 前端开发
jvm之.class文件解读(上)
jvm之.class文件解读(上)
|
Arthas 存储 Java
class 和 Classloader 相关命令:dump | 学习笔记
快速学习 class 和 Classloader 相关命令:dump
class 和 Classloader 相关命令:dump | 学习笔记
|
Arthas 测试技术 编译器
class 和 classloader 相关命令:jad 和 mc | 学习笔记
快速学习 class 和 classloader 相关命令:jad 和 mc
class 和 classloader 相关命令:jad 和 mc | 学习笔记
|
Arthas Java 测试技术
classloader 命令的使用 | 学习笔记
快速学习 classloader 命令的使用
classloader 命令的使用 | 学习笔记
|
Arthas Java 测试技术
class 和 classloader 相关命令: sc 和 sm | 学习笔记
快速学习 class 和 classloader 相关命令: sc 和 sm
class 和 classloader 相关命令: sc 和 sm | 学习笔记