我正在使用attach API在运行时加载JVMTI代理。 我希望在程序完成时卸载JVMTI代理,而不终止加载代理的JVM。 根据这份文档,从attach API中没有方法可以做到这一点。是否有其他方法可以通过Java API或JVMTI代理内部来强制代理自行卸载?
我正在使用attach API在运行时加载JVMTI代理。 我希望在程序完成时卸载JVMTI代理,而不终止加载代理的JVM。 根据这份文档,从attach API中没有方法可以做到这一点。是否有其他方法可以通过Java API或JVMTI代理内部来强制代理自行卸载?
你需要通过程序来加载JVMTI代理:
// attach to target VM
VirtualMachine vm = VirtualMachine.attach("2177");
// get system properties in target VM
Properties props = vm.getSystemProperties();
// construct path to management agent
String home = props.getProperty("java.home");
String agent = home + File.separator + "lib" + File.separator
+ "your-agent-example.jar";
// load agent into target VM
vm.loadAgent(agent, "com.sun.management.jmxremote.port=5000");
// detach
vm.detach();
查看此处的文档
之后,您必须使用与默认值不同的classLoad:
您必须将系统属性“java.system.class.loader”设置为您的目标JVM的自定义类加载器的名称。
查看此处的文档
“Java的内置类加载器在加载类之前始终检查是否已加载该类。因此,使用Java的内置类加载器无法重新加载类。要重新加载类,您必须实现自己的ClassLoader子类。”
在您的情况下,您必须实现一个ClassLoader,其中ClassLoader.getSystemClassLoader()是父级。
即使使用自定义的ClassLoader子类,您仍然会面临挑战。每个加载的类都需要链接。这是使用ClassLoader.resolve()方法完成的。该方法是final的,因此无法在您的ClassLoader子类中重写。resolve()方法不允许任何给定的ClassLoader实例链接同一个类两次。因此,每次想要重新加载类时,必须使用ClassLoader子类的新实例。这并非不可能,但在设计类重新加载时需要知道这一点。