Javaagent类卸载
我有一个用于检测字节码的java代理。 我使用 java 6 中的附加 API 来允许用户使用我的 java 代理动态加载代理和仪器和反仪器代码。 我使用 Boot-Class-Path 清单属性来确保我的 javagent 类位于启动类路径中,以便我的用户可以检测 ArrayList 等类。
但是问题来自于版本控制。 假设用户动态附加我的代理的版本 1。 然后我给了他版本 2。现在,由于他附加了我的代理的版本 1,他的应用程序服务器从未关闭过,所以版本 1 的类仍然加载。
我需要某种方法,以便当我的客户端版本 2 的 javaagent 时,版本 1 被卸载。
我知道一种方法是为我的 javaagent 类编写一个客户类加载器,并将类加载器引用设置为 null。 然而,在这种情况下,我将无法在引导类路径中检测类,因为我的类加载器将位于引导类加载器的层次结构中的下方,因此我的用户无法检测像 ArrayList 这样的类,因为如果我在 ArrayList 的方法内部添加对我的其中一个方法的调用,代理类的方法引导类加载器将无法看到它们。
那么有什么方法可以解决启动类路径问题并仍然卸载以前的代理的类吗?
I have a java agent which instruments bytecode.
I am using the attach apis in java 6 to allow users to dynamically load the agent and instrument and deinstrument code using my java agent.
I am using the Boot-Class-Path manifest attribute to make sure my javagent classes are in the boot classpath so that my users can instrument classes like ArrayList, etc.
However the problem comes with versioning.
Lets say a user dynamically attaches version 1 of my agent.
Then I given him version 2. Now since his app server never shut down since he attached version 1 of my agent, the version 1 classes are still loaded.
I need some way such that when my client version 2 of the javaagent, the version 1 is unloaded.
I know one way would be to write a customer classloader for my javaagent's classes, and set the classloader reference to null.
However in that case I wont be able to instrument classes in the boot classpath since my classloader will be below in the hierarchy from the boot classloader and thus my users cant instrument classes like ArrayList because if I add a call inside ArrayList's methods to one of my agent's classes' methods the boot class loader wont be able to see them.
So is there any way to solve the boot classpath issue and still unload the previous agent's classes?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
我不是这个主题的专家,但似乎不直接支持这种卸载替换。
但是你需要卸载-替换这个类吗?
您能否创建一个与外部世界对话的永不改变的类,在其中内部实现版本控制系统?
例如,您创建的类 MyToolAgent 具有一个静态字符串,其中包含要使用的 ToolAgentImplementation 的类名。 首次发布时,它设置为使用 ToolAgentImplementation1_0。 升级到版本 2.0 时,您将部署一个名为 ToolAgentImplmenetation2_0 的附加类,并更新 MyToolAgent 类以加载和使用它。 您永远不会卸载版本 1.0,但您确实会停止使用它。 这里确实浪费了一些内存,但是实现了版本升级。
我不知道这在你的情况下是否可行,但总的来说,JVM 似乎不支持直接交换新版本,但你应该能够以某种方式隐藏它。
I'm not an expert on this topic, but it seems like this kind of unload-to-replace is not directly supported.
But do you need to unload-replace the class?
Could you instead create a never-changing class that the external world talks to, in which you internally imlpement a versioning system?
For example, you create class MyToolAgent that has, say, a static string with the classname of the ToolAgentImplementation to use. When you first release, it's set to use ToolAgentImplementation1_0. When you upgrade to version 2.0, you deploy an additional class called ToolAgentImplmenetation2_0, and update the MyToolAgent class to load and use it. You never unload version 1.0, but you do stop using it. You do waste some memory here, but you achieve the version upgrade.
I don't know if this is feasible in your situation, but in general it seems the JVM doesn't support directly swapping in a new version, but that you should be able to hide that in some way.
我现在还没有检测任何东西,但我只是在玩 java.util.ServiceLoader 并实现了某种插件架构,使用 URLClassLoader 的方法进行动态 JAR 加载卸载。
我不知道可以通过这种方式更改“仪器”,但是可以跟踪版本控制和动态加载卸载问题,并且测试它的速度非常快,因为困难的事情是由 ServiceLoader 完成的(只需遵循微小的/META-INF/services/XXX 规范),您已准备好:)
问候。
I haven't instrumented anything by now but I'm just playing with java.util.ServiceLoader and implemented some kind of plugin architecture, with dynamic JAR load-unload with your URLClassLoader's approach.
I don't know the "instrumentation" could be altered this way but the versioning and the dynamic load-unload problems can be tracked down, and it's really fast to test it because the hard stuff is done by the ServiceLoader (just follow the tiny /META-INF/services/XXX specification) and you are ready :)
Regards.
我不确定这是否有效,但它可能会给您一些选择...
而不是尝试重新加载当前代理(我们称之为工具代理),而是添加一个新代理(安装程序代理)。 安装程序代理只有 1 个功能:使用 RedefineClasses() 替换原始工具代理类。
如果您使用版本号作为类名的一部分来命名安装程序代理 (MyToolInstallerV1),则可以继续加载更新工具代理的新安装程序。 如果大小成为问题,也许安装程序代理可以查找以前的安装程序并用小的无操作存根替换它们的类。
I'm not sure this will work, but it may give you some options...
Instead of trying to reload the current agent (let's call this the tool agent), add a new agent (an installer agent). The installer agent would have exactly 1 function: use RedefineClasses() to replace the original tool agent classes.
If you name the installer agent with a version number as part of the classname (MyToolInstallerV1), you can keep loading new installers that update the tool agent. If size becomes an issue, perhaps an installer agent could look for previous installers and replace their classes with a small no-op stub.
OSGI 的完美用例。 但不确定您是否可以将代理作为捆绑包插入。
Perfect use case for OSGI. Not sure whether you could plug your agent as a bundle though.