使用自定义java代理打包jar文件时,可以添加以下属性:
Can-Redefine-Classes
Can-Retransform-Classes
这两者有什么区别?
如果重新定义发生在类加载和重新转换之后,那么什么时候发生了完全重新转换?
答案 0 :(得分:6)
它们为我们提供的功能似乎几乎是多余的。主要的区别似乎是当我们重新定义一个类时,我们提供了一个byte[]
的新定义,而当我们重新转换时,我们通过相同的API获取包含当前定义的byte[]
,然后返回修改后的byte[]
。
因此,要重新定义,我们需要了解有关该课程的更多信息。考虑注入性能分析跟踪语句的用例。使用转换,您可以更直接地执行此操作:只需查看给定的字节码,修改它并返回它。但是,如果我们选择了重定义路线,我们需要从某个位置(例如byte[]
)获取原始getResourceAsStream()
。
另一个明显的区别在于我们如何与其他类变压器互动;谁先走了变换应用于原始类或重新定义的类,因此可以添加几个变换,例如。
从历史上看,如果我们在API documentation或this book的第238页(Friesen 2007 Beginning Java SE 6平台)中查看从评论 em>),我们注意到Java 5中引入了重新定义功能,Java 6中引入了重新转换。我的猜测是重新转换引入了一般功能,但必须保留重新定义以实现向后兼容。
从上面链接的书中引用关于重新转换方法的关键句子:
代理使用这些方法重新转换以前加载的类 无需访问其类文件。
问题的第二部分:
如果在加载和重新转换类之前重新定义 之后,那么什么时候才能完全重新转换?
不,重载定义在加载类之后发生,以及重新转换。当您分别调用Instrumentation
实例的redefineClasses(..)
和retransformClasses(..)
方法时,就会发生这种情况。
对于任何经过专家的问题,这是一个问题:您是否可以通过重新定义类来执行此操作,而重新转换这些类无法做到?我的猜测是答案是“没有”。
答案 1 :(得分:4)
重新定义意味着在任意时间点,代理将调用Instrumentation。 redefineClasses更改现有(和已加载)类的实际定义。代理将为新定义提供字节码。
重新转换是指类文件转换的过程,通常在类加载时应用。代理可以注册一个接一个地调用的ClassFileTransformer,以在初始化类之前将转换应用于字节代码。因此,Retransformation指的是JVM为已经加载的类重复此过程的能力。在这种情况下,代理可以调用Instrumentation.retransformClasses,指定要重新转换但没有字节码的类。相反,JVM将调用所有已注册的可重新转换的ClassFileTransformers,提供实际的字节码(或链式变换器的前一个变换器的结果)。
答案 2 :(得分:0)
重新转换:
转换是指类文件转换的过程,通常在类加载时应用。代理可以注册ClassFileTransformers,它们将被依次调用,以便在初始化类之前对字节码进行转换。因此,重新转换是指JVM对已经加载的类重复此过程的功能。
重新转换与检测类/方法具有相同的功能,但适用于已加载的类。
有关重新转换的问题: JVM将字节码存储在PermGen(Java 7或更低版本)或Metaspace(Java 8或更高版本)中。每次代理重新转换类/方法时,JVM会将修改后的字节码的副本保存在PermGen或Metaspace中。过度的重新转换会导致内存泄漏。
IBM Java有额外10%的CPU开销用于重新转换。这就是为什么在IBM Java Agent中禁用重新转换的原因。 约80%的JVM崩溃是由于重新转换-这并不意味着JVM大多数时候都崩溃了,但是每当我们遇到JVM崩溃问题时,约80%的时间就是由于重新转换。
禁用重新转换: 有一个Java选项系统属性(-Dappdynamics.agent.disable.retransformation = true)可禁用重新转换