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:将字节码文件重新加载到内存中执行

相关文章
|
SQL 监控 关系型数据库
【MYSQL高级】Mysql找出执行慢的SQL【慢查询日志使用与分析】
【MYSQL高级】Mysql找出执行慢的SQL【慢查询日志使用与分析】
5527 0
|
NoSQL 数据可视化 关系型数据库
推荐几个好用的redis可视化工具
推荐几个好用的redis可视化工具
17971 1
|
8月前
|
数据采集 JSON 搜索推荐
AI+代理IP手把手教你爬取某度
AI+代理IP手把手教你爬取某度
407 0
|
安全 Java Python
instanceof 的实现原理
`instanceof` 是 Java 中的一个关键字,用于判断一个对象是否属于某个类或其子类。其原理是通过检查对象的类层次结构,确定该对象是否是指定类的实例。具体实现涉及对象头中的类元数据信息和类加载器的作用。
|
人工智能 自然语言处理 数据库
RAG 技术:让 AI 从 “书呆子” 变身 “开卷小天才”!
鳄叔介绍了RAG(检索增强生成)技术,这是一种让AI既能查资料又能灵活作答的方法,如同“开卷考试”的学霸。RAG结合了检索能力和生成能力,使AI能够实时获取最新信息,提供更专业、精准的回答,广泛应用于企业客服、法律咨询、医疗诊断和教育等领域。
347 0
|
存储 监控 Cloud Native
最牛逼的性能监控系统,SkyWalking 集强大于一身!
最牛逼的性能监控系统,SkyWalking 集强大于一身!
2201 0
最牛逼的性能监控系统,SkyWalking 集强大于一身!
|
存储 安全 网络协议
邮件协议揭秘:SMTP与IMAP的双重功能解析
SMTP和IMAP是电子邮件系统的核心协议,SMTP负责邮件发送,通过SSL/TLS保证安全,而IMAP则处理邮件接收和管理,支持服务器存储及状态同步。这两种协议相辅相成,为现代邮件系统提供了坚实基础。它们广泛应用于各种邮件客户端,确保了兼容性、功能丰富性和安全性,满足用户对电子邮件的多样化需求。
909 3
|
Java Perl
JVM内存问题之如何统计在JVM的类加载中,每一个类的实例数量,并按照数量降序排列
JVM内存问题之如何统计在JVM的类加载中,每一个类的实例数量,并按照数量降序排列
314 0
|
前端开发 JavaScript
CSS【实战】抽屉动画
CSS【实战】抽屉动画
328 0
|
监控 安全 Java
JVM工作原理与实战(三十八):JIT即时编译器原理
JVM作为Java程序的运行环境,其负责解释和执行字节码,管理内存,确保安全,支持多线程和提供性能监控工具,以及确保程序的跨平台运行。本文主要介绍了JIT即时编译器、HotSpot中的JIT编译器、JIT优化技术、JIT优化建议等内容。
418 0