[alibaba/arthas]使用retransform命令后用stop命令退出后再次登上去然后用jad查看源码的话字节码会被还原

2024-04-24 292 views
4
环境信息
  • arthas-boot.jar 或者 as.sh 的版本: xxx
  • Arthas 版本: 3.5.3
  • 操作系统版本: Win10
  • 目标进程的JVM版本: Java(TM) SE Runtime Environment (build 1.8.0_111-b14)
  • 执行arthas-boot的版本: 3.5.3
重现问题的步骤
  1. 先跑一个简单的java代码
    
    package com;

import java.util.concurrent.TimeUnit;

public class Test {

public static void main(String[] args) {

    Test a = new Test();

    while (true) {
        a.abc();
        try {
            TimeUnit.SECONDS.sleep(2);
        } catch (Exception e) {

        }
    }

}

public void abc() {
    System.out.println("abc");
}

}

运行,会每隔一秒打印"abc"
2.然后在abc方法体里多加一行的代码
```java
    public void abc() {
        System.out.println("abc");
        System.out.println("dddd");  // 新增加的
    }
  1. 使用retransform修改字节码 retransform Test.class
  2. 发现每隔一秒会打印 "abc"和"dddd"
  3. 使用jad命令也能看到被修改的代码
  4. 使用stop命令退出来
  5. 重新使用java -jar arthas-boot.jar登上去
  6. 直接使用jad命令再次查看代码
期望的结果

第8步应该还是修改过的代码

实际运行的结果

实际结果是代码被还原。最终打印的是abc 按照文档的说法是 retransform + jad是不会还原字节码的。但是目前按照我上面的步骤。就必现 也就是如果是第一次java -jar arthas-boot.jar登录上去,然后用retransform修改字节码,再马上用jad去看的话。不会被还原。一旦用stop命令退出后,再次登上去,这时候如果用jad去看就会被还原

回答

8

因为 retransform 的实现最终是 注册了一个 transformer ,在里面转换完成的。参考retransform wiki里jdk的文档。

当arthas stop时,自然会把这个 transformer 注销掉。 然后 arthas第二次 attach时,就会出一个新的 transformer ,然后当用jad命令再次触发了 jdk的 retransform 过程时,第一次的 transformer 没有了,自然就会还原来原来的结果了。

参考: https://github.com/alibaba/arthas/issues/763

2

因为 retransform 的实现最终是 注册了一个 transformer ,在里面转换完成的。参考retransform wiki里jdk的文档。

当arthas stop时,自然会把这个 transformer 注销掉。 然后 arthas第二次 attach时,就会出一个新的 transformer ,然后当用jad命令再次触发了 jdk的 retransform 过程时,第一次的 transformer 没有了,自然就会还原来原来的结果了。

参考: #763

那后续的版本有没有可能会解决该问题

6

实现机制就是这样,stop的语义就是完全停止,不把 transformer 注销掉是不可能的。目前没看到可以改进的地方。

8

实现机制就是这样,stop的语义就是完全停止,不把 transformer 注销掉是不可能的。目前没看到可以改进的地方。

明白。感谢老哥的解答

2

实现机制就是这样,stop的语义就是完全停止,不把 transformer 注销掉是不可能的。目前没看到可以改进的地方。

请问为什么一定要将transformer 注销掉呢?

4

实现机制就是这样,stop的语义就是完全停止,不把 transformer 注销掉是不可能的。目前没看到可以改进的地方。

请问为什么一定要将transformer 注销掉呢?

transformer 本身就是一个class,它是由arthas classloader加载的。不移除掉,arthas classloader就会一直存在,没办法被jvm回收。这和arthas stop 语义不符。

6

实现机制就是这样,stop的语义就是完全停止,不把 transformer 注销掉是不可能的。目前没看到可以改进的地方。

请问为什么一定要将transformer 注销掉呢?

transformer 本身就是一个class,它是由arthas classloader加载的。不移除掉,arthas classloader就会一直存在,没办法被jvm回收。这和arthas stop 语义不符。

好的,明白了,感谢解答。

6

因为 retransform 的实现最终是 注册了一个 transformer ,在里面转换完成的。参考retransform wiki里jdk的文档。

当arthas stop时,自然会把这个 transformer 注销掉。 然后 arthas第二次 attach时,就会出一个新的 transformer ,然后当用jad命令再次触发了 jdk的 retransform 过程时,第一次的 transformer 没有了,自然就会还原来原来的结果了。

参考: #763

你好,我现在用的arthas版本是3.1.4,很老的一个版本,在这个版本里在enhance里进行插桩后,会立即将transformer给remove掉,但是这样会存在如果有其他agent或者jad命令如果执行了retransform,会将之前插桩的内容给移除掉!而在3.3.0版本中,添加了TransformManager类对所有的transformer进行统一管理,而removeTransformer的操作也放到了stop命令之后。我想问下,在以前的版本,为什么插桩后要立即removeTransformer呢?是考虑性能问题?因为从缓存里取字节码,所有不需要transformer了?还有如果我不想升级版本,对当前版本代码进行修改,也想将removeTransformer操作放在stop中,除了添加TransformManager类,还需要考虑其他关键的事项吗?期望收到回答,谢谢!

7

你好,我现在用的arthas版本是3.1.4,很老的一个版本,在这个版本里在enhance里进行插桩后,会立即将transformer给remove掉,但是这样会存在如果有其他agent或者jad命令如果执行了retransform,会将之前插桩的内容给移除掉!而在3.3.0版本中,添加了TransformManager类对所有的transformer进行统一管理,而removeTransformer的操作也放到了stop命令之后。我想问下,在以前的版本,为什么插桩后要立即removeTransformer呢?是考虑性能问题?因为从缓存里取字节码,所有不需要transformer了?还有如果我不想升级版本,对当前版本代码进行修改,也想将removeTransformer操作放在stop中,除了添加TransformManager类,还需要考虑其他关键的事项吗?期望收到回答,谢谢!

之前的版本设计不是很好。建议升级,不建议用旧的。