简体   繁体   English

javaagent中redefine和retransform的区别

[英]Difference between redefine and retransform in javaagent

When packing a jar file with custom java agent, you can add the following properties:使用自定义 java 代理打包 jar 文件时,可以添加以下属性:

  • Can-Redefine-Classes
  • Can-Retransform-Classes

What is the difference between those two?这两者有什么区别?

If redefinition happens before class is loaded and retransformation after, then when does exactly retransformation happen?如果重定义发生在类加载之前并在类加载之后重新转换,那么真正的重新转换发生在什么时候?

They seem almost redundant in the functionality they offer us.它们为我们提供的功能似乎几乎是多余的。 The main difference seems to be that when we redefine a class, we supply a 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[] ,而当我们retransform 时,我们通过相同的 API 获得了一个包含当前定义的byte[] ,我们返回修改后的byte[]

Therefore, to redefine , we need to know more about the class.因此,要重新定义,我们需要更多地了解该类。 Consider the use-case of injecting profiling trace statements.考虑注入分析跟踪语句的用例。 With retransform you can do that more directly: just look at the bytecode given, modify it, and return it.使用retransform,您可以更直接地做到这一点:只需查看给定的字节码,修改它,然后返回它。 But if we went the redefine route, we would need to fetch the original byte[] from somewhere (like getResourceAsStream() ).但是,如果我们采用重新定义的路线,则需要从某个地方(如getResourceAsStream() )获取原始byte[]

Another apparent difference is in how we interact with other class transformers;另一个明显的区别在于我们如何与其他类转换器交互; who goes first.谁先走。 Transforms are applied to the original or a redefined class, so several transforms can be additive, for example.例如,转换应用于原始类或重新定义的类,因此可以添加多个转换。

Historically, if we look at the Since comments in the API documentation , or on page 238 of this book (Friesen 2007 Beginning Java SE 6 Platform ), we notice that redefinition capabilities were introduced in Java 5, and retransformation in Java 6. My guess is that retransformation was introduced as a more general capability, but redefinition had to be retained for backwards compatibility.从历史上看,如果我们查看API 文档中或本书第 238 页(Friesen 2007开始 Java SE 6 平台)中的注释,我们会注意到 Java 5 中引入了重新定义功能,Java 6 中引入了重新转换。我的猜测是作为更通用的功能引入了重新转换,但必须保留重新定义以向后兼容。

Quoting the key sentence about retransformation methods from the book linked above:引用上面链接的书中关于重新转换方法的关键句子:

Agents use these methods to retransform previously loaded classes without needing to access their class files.代理使用这些方法重新转换以前加载的类,而无需访问它们的类文件。


The second part of the question:问题的第二部分:

If redefinition happens before class is loaded and retransformation after, then when does exactly retransformation happen?如果重定义发生在类加载之前并在类加载之后重新转换,那么真正的重新转换发生在什么时候?

No, redefinition happens after the class is loaded, as well as retransformation.不,重新定义发生在类加载之后,以及重新转换。 They happen when you call your Instrumentation instance's redefineClasses(..) and retransformClasses(..) methods, respectively.它们分别在您调用Instrumentation实例的redefineClasses(..)retransformClasses(..)方法时发生。

Here is a question to any experts passing by: is there anything you can do by redefining classes, that you can't do by retransforming them?这是对路过的任何专家的一个问题:有什么事情可以通过重新定义类来做而不能通过重新转换来做吗? My guess is that the answer is "nothing".我的猜测是答案是“没有”。

Redefinition means that at an arbitrary point of time an agent will invoke Instrumentation.重新定义意味着在任意时间点代理将调用 Instrumentation。 redefineClasses to change the actual definition of existing (and already loaded) classes. redefineClasses 更改现有(和已加载)类的实际定义。 The agent will provide the bytecode for the new definition.代理将为新定义提供字节码。

Retransformation refers to the process of class file transformation which is normally applied at class loading time.重新转换是指类文件转换的过程,通常在类加载时应用。 Agents can register ClassFileTransformers which are called one after another to apply transformations to the byte code before the class will be initialized.代理可以注册一个又一个被调用的 ClassFileTransformers,以便在类初始化之前将转换应用于字节码。 So Retransformation refers to the capability of the JVM to repeat this process for already loaded classes.因此,重新转换是指 JVM 对已加载的类重复此过程的能力。 In this case an agent may invoke Instrumentation.retransformClasses specifying which classes to retransform but no bytecode.在这种情况下,代理可以调用​​ Instrumentation.retransformClasses 指定要重新转换的类,但没有字节码。 Instead the JVM will call all registered retransforming capable ClassFileTransformers providing the actual bytecode (or the result of the previous transformer for a chained transformer).相反,JVM 将调用所有已注册的具有重新转换能力的 ClassFileTransformers,提供实际的字节码(或链式转换器的前一个转换器的结果)。

Retransformation:改造:

Transformation refers to the process of class file transformation which is normally applied at class loading time.转换是指类文件转换的过程,通常在类加载时应用。 Agents can register ClassFileTransformers which are called one after another to apply transformations to the byte code before the class will be initialized.代理可以注册一个又一个被调用的 ClassFileTransformers,以便在类初始化之前将转换应用于字节码。 So Retransformation refers to the capability of the JVM to repeat this process for already loaded classes.因此,重新转换是指 JVM 对已加载的类重复此过程的能力。

Retransformation is the same capabilities as instrumenting the classes/methods but for the loaded classes.重新转换与检测类/方法的功能相同,但适用于加载的类。

Issues with Retransformation: JVM stores bytecode in PermGen (Java 7 or lower) or Metaspace (Java 8 or higher).重新转换问题:JVM 将字节码存储在 PermGen(Java 7 或更低版本)或元空间(Java 8 或更高版本)中。 Every time an agent retransforms the class/method, JVM saves a copy of the modified bytecode in PermGen or Metaspace.每次代理重新转换类/方法时,JVM 都会在 PermGen 或 Metaspace 中保存修改后的字节码的副本。 Excessive retransformation can lead memory leaks.过度的重新转换会导致内存泄漏。

IBM Java has additional 10% CPU overhead for retransformation. IBM Java 有额外 10% 的 CPU 开销用于重新转换。 That is why retransformation is disabled in IBM Java agent.这就是 IBM Java 代理中禁用重新转换的原因。 ~80% of all JVM crashes are due to retransformation - This does not mean that JVM crashes most of the time but whenever we face JVM crash issue, ~80% of the time is because of retransformation.大约 80% 的 JVM 崩溃是由于重新转换造成的——这并不意味着 JVM 大部分时间都会崩溃,但是每当我们面临 JVM 崩溃问题时,大约 80% 的时间是因为重新转换。

Disable Retransformation: There is a java option system property (-Dappdynamics.agent.disable.retransformation=true) to disable retransformation禁用重新转换:有一个 java 选项系统属性(-Dappdynamics.agent.disable.retransformation=true)来禁用重新转换

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM