不重启JVM,替换掉已经加载的类

不重启JVM,替换掉已经加载的类

直接操作字节码

使用ASM框架直接操作class文件,在类中修改代码,然后retransform就可以了

下边是BTrace官方提供的一个简单例子:

java 复制代码
package com.sun.btrace.samples;

import com.sun.btrace.annotations.*;
import com.sun.btrace.AnyType;
import static com.sun.btrace.BTraceUtils.*;

/**
 * This sample demonstrates regular expression
 * probe matching and getting input arguments
 * as an array - so that any overload variant
 * can be traced in "one place". This example
 * traces any "readXX" method on any class in
 * java.io package. Probed class, method and arg
 * array is printed in the action.
 */
@BTrace public class ArgArray {
    @OnMethod(
        clazz="/java\\.io\\..*/",
        method="/read.*/"
    )
    public static void anyRead(@ProbeClassName String pcn, @ProbeMethodName String pmn, AnyType[] args) {
        println(pcn);
        println(pmn);
        printArray(args);
    }
}

另一个例子:每隔2秒打印截止到当前创建过的线程数

java 复制代码
package com.sun.btrace.samples;

import com.sun.btrace.annotations.*;
import static com.sun.btrace.BTraceUtils.*;
import com.sun.btrace.annotations.Export;

/**
 * This sample creates a jvmstat counter and
 * increments it everytime Thread.start() is
 * called. This thread count may be accessed
 * from outside the process. The @Export annotated
 * fields are mapped to jvmstat counters. The counter
 * name is "btrace." + <className> + "." + <fieldName>
 */ 
@BTrace public class ThreadCounter {

    // create a jvmstat counter using @Export
    @Export private static long count;

    @OnMethod(
        clazz="java.lang.Thread",
        method="start"
    ) 
    public static void onnewThread(@Self Thread t) {
        // updating counter is easy. Just assign to
        // the static field!
        count++;
    }

    @OnTimer(2000) 
    public static void ontimer() {
        // we can access counter as "count" as well
        // as from jvmstat counter directly.
        println(count);
        // or equivalently ...
        println(Counters.perfLong("btrace.com.sun.btrace.samples.ThreadCounter.count"));
    }
}

BTrace主要模块:

  • BTrace脚本:利用BTrace定义的注解,我们可以很方便地根据需要进行脚本的开发。
  • Compiler:将BTrace脚本编译成BTrace class文件。
  • Client:将class文件发送到Agent。
  • Agent:基于Java的Attach API,Agent可以动态附着到一个运行的JVM上,然后开启一个BTrace
  • Server,接收client发过来的BTrace脚本;解析脚本,然后根据脚本中的规则找到要修改的类;修改字节码后,调用Java Instrument的retransform接口,完成对对象行为的修改并使之生效。

BTrace的架构大致如下:

BTrace最终借Instrument实现class的替换。

BTrace脚本的限制如下:

  1. 不允许创建对象
  2. 不允许创建数组
  3. 不允许抛异常
  4. 不允许catch异常
  5. 不允许随意调用其他对象或者类的方法,只允许调用com.sun.btrace.BTraceUtils中提供的静态方法(一些数据处理和信息输出工具)
  6. 不允许改变类的属性
  7. 不允许有成员变量和方法,只允许存在static public void方法
  8. 不允许有内部类、嵌套类
  9. 不允许有同步方法和同步块
  10. 不允许有循环
  11. 不允许随意继承其他类(当然,java.lang.Object除外)
  12. 不允许实现接口
  13. 不允许使用assert
  14. 不允许使用Class对象

如此多的限制,其实可以理解。BTrace要做的是,虽然修改了字节码,但是除了输出需要的信息外,对整个程序的正常运行并没有影响。

Arthas把一些BTrace脚本常用的功能封装起来,对外直接提供简单的命令即可操作的话,

相关推荐
unclecss2 小时前
把 Spring Boot 的启动时间从 3 秒打到 30 毫秒,内存砍掉 80%,让 Java 在 Serverless 时代横着走
java·jvm·spring boot·serverless·graalvm
q***2514 小时前
java进阶1——JVM
java·开发语言·jvm
zlpzlpzyd4 小时前
jvm 偏向锁禁用以及移除
jvm
while(1){yan}4 小时前
线程的状态
java·开发语言·jvm
20岁30年经验的码农4 小时前
Java JVM 技术详解
java·jvm·压力测试
1***81534 小时前
C在游戏中的场景管理
java·jvm·游戏
上78将4 小时前
jvm的基本结构
jvm
Tan_Ying_Y4 小时前
JVM内存结构———他的底层完整结构
jvm
张人玉4 小时前
SQLite语法知识和使用实例
jvm·oracle·sqlite
艾斯比的日常5 小时前
JVM 内存结构:全面解析与面试重点
jvm·面试·职场和发展