【发布时间】:2020-07-04 16:04:38
【问题描述】:
我制作了一个 Java 代理,它在 运行时 期间附加到 JVM,并检测所有加载的项目类并插入一些日志记录语句。总共有 11k 个类。我测量了我的ClassFileTransformer 的transform 方法所花费的总时间,它是3 秒。但是整个检测过程的持续时间大约需要 30 秒。
这就是我重新转换我的课程的方式:
instrumentation.retransformClasses(myClassesArray);
我假设 JVM 占用了大部分时间来重新加载更改的类。是对的吗?如何加快检测过程?
更新:
当我的代理被附加时,
instrumentation.addTransformer(new MyTransfomer(), true);
instrumentation.retransformClasses(retransformClassArray);
只被调用一次。
然后MyTransfomer 类检测类并测量检测的总持续时间:
public class MyTransfomer implements ClassFileTransformer {
private long total = 0;
private long min = ..., max = ...;
public final byte[] transform(ClassLoader loader, String className, Class<?> classBeingRedefined, ProtectionDomain protectionDomain, byte[] classFileBuffer) {
long s = System.currentTimeMillis();
if(s < min) min = s;
if(s > max) max = s;
byte[] transformed = this.transformInner(loader, className, classFileBuffer);
this.total += System.currentTimeMillis() - s;
return transformed;
}
}
检测所有类后(从初始数组)(全局缓存跟踪检测的类)total 被打印出来,大约需要 3 秒。但是max-min 大约是 30 秒。
更新 2:
查看堆栈跟踪后会发生以下情况: 我打电话
instrumentation.retransformClasses(retransformClassArray);
调用本机方法retransformClasses0()。一段时间后(!)JVM调用sun.instrument.InstrumentationImpl类的transform()方法(但是这个方法一次只需要一个类,所以JVM连续多次调用这个方法),它调用transform() sun.instrument.TransformerManager 对象有一个列表,其中包含所有已注册的 ClassTransformers 并调用这些转换器中的每一个来转换类(我只注册了一个转换器!!)。
所以在我看来,大部分时间都花在了 JVM 上(在调用 retransformClasses0() 之后和每次调用 sun.instrument.InstrumentationImpl.transform() 之前)。有没有办法减少 JVM 执行此任务所需的时间?
【问题讨论】:
-
如果没有源代码、java 版本和类路径,几乎是不可能提供帮助的。你能把它添加到问题中或创建一个 github 项目吗?
-
@Jeff 更新了代码。
-
真的需要看看,如果可能的话,transformInner 在做什么。另外我建议记录每个类的执行时间,看看是否有特定的类有问题。
-
JVM中是否注册了其他类文件转换器?
-
@Holger,没有
标签: java instrumentation javaagents