我编写了一个Java代理,其中一个实例在下面的方法中实现components.xml
:
ClassFileTransformer
为了能够重新转换已加载的类,我使用下面的方法添加上面的转换器:
class MyTransformer {
public byte[] transform(ClassLoader loader, String classNameWithSlash,
Class classBeingRedefined, ProtectionDomain protectionDomain,
byte[] classfileBuffer) throws IllegalClassFormatException {
return null;
}
}
它在功能上有效,但有一个问题:
使用Oracle JDK1.8.0_102(在Linux 64位上)进行测试时,通过在JVM启动参数中添加以下参数来启用类加载和卸载的跟踪
inst.addTransformer(new MyTransformer(), true);
。调用-XX:+TraceClassLoading -XX:+TraceClassUnloading
时,我可以看到类加载的跟踪日志,例如
inst.retransform(aClass)
这对于类加载很好,但是当我再次重新转换同一个类时,我可以看到这个' loading'再次跟踪日志,但无法看到与卸载相关的任何跟踪。
所以问题是,如果我将[Loaded myapp.MyClass from __VM_RedefineClasses__]
调用一定次数,JVM崩溃!当我增加inst.retransform()
的设置时,我可以在JVM崩溃之前增加调用次数。这两个数字高度相关,。
那么,问题:这是一个JVM错误,还是代理开发人员卸载正在转换的类的工作?
注意:即使我的变换器没有通过返回-XX:MetaspaceSize
进行任何转换,JVM也会崩溃(或抱怨元空间内存不足)。
答案 0 :(得分:0)
当使用类的功能但是无法以类似的方式执行卸载时,加载的类是默认行为。卸载类由GC完成。 GC在卸载类之前执行一些启发式检查。这不是一个错误。 JVM正在按设计工作。