当使用自定义Java代理程序打包JAR文件时,您可以添加以下属性:
Can-Redefine-Classes
:允许重新定义类。Can-Retransform-Classes
:允许重转换类。
这两者之间有什么区别?
如果重新定义发生在类加载之前,而重转换发生在之后,那么重转换是何时发生的?
当使用自定义Java代理程序打包JAR文件时,您可以添加以下属性:
Can-Redefine-Classes
:允许重新定义类。Can-Retransform-Classes
:允许重转换类。这两者之间有什么区别?
如果重新定义发生在类加载之前,而重转换发生在之后,那么重转换是何时发生的?
byte[]
with the new definition out of the blue, whereas when we retransform, we get a byte[]
containing the current definition via the same API, and we return a modified byte[]
.byte[]
from somewhere (like getResourceAsStream()
).从历史上看,如果我们查看API文档中的Since注释,或者在这本书(Friesen 2007 Beginning Java SE 6 Platform)的第238页上,我们会注意到重定义功能是在Java 5中引入的,而重转换则是在Java 6中引入的。我猜重转换被引入作为一种更通用的能力,但为了向后兼容性,必须保留重定义。
引用上述链接书籍中关于“重新转换”方法的关键句子:Instrumentation
实例的redefineClasses(..)
和retransformClasses(..)
方法时,分别执行重定义和重转换操作。重新转换:
转换是指在类加载时通常应用的类文件转换过程。代理可以注册ClassFileTransformers,这些转换器会依次调用以在类初始化之前对字节码应用转换。因此,重新转换是JVM重复对已加载类执行此过程的能力。
重新转换与为已加载类进行类/方法检测具有相同的功能。
重新转换存在的问题: JVM将字节码存储在PermGen(Java 7或更低版本)或Metaspace(Java 8或更高版本)中。每次代理重新转换类/方法时,JVM都会在PermGen或Metaspace中保存修改后的字节码副本。过度的重新转换可能导致内存泄漏。
IBM Java在重新转换方面有额外的10% CPU开销。这就是为什么在IBM Java代理中禁用重新转换的原因。 大约80%的JVM崩溃是由于重新转换-这并不意味着JVM大部分时间都会崩溃,但每当我们遇到JVM崩溃问题时,大约80%的时间是由于重新转换造成的。
禁用重新转换: 有一个Java选项系统属性(-Dappdynamics.agent.disable.retransformation=true)可用于禁用重新转换。