【问题标题】:How to unload agent which loaded by loadAgent()如何卸载由 loadAgent() 加载的代理
【发布时间】:2013-11-26 02:56:39
【问题描述】:

我正在使用 jdk1.6。我已经在运行时成功加载了一个 jar。代码如下:

vm = VirtualMachine.attach(vid);
vm.loadAgent(agentPath);

现在我想在运行时卸载这个代理。没有 API DOC 可以做到这一点。谁能给我一些建议?谢谢。

编辑

更多代码

GlobalVariables.vm = VirtualMachine.attach(vid);

// Check to see if transformer agent is installed
if(!GlobalVariables.vm.getSystemProperties().contains("demo.agent.installed")) {
    System.out.println("Load agent");

    GlobalVariables.vm.loadAgent(agentPath); 

}

GlobalVariables.connectorAddress = GlobalVariables.vm.getAgentProperties().getProperty("com.sun.management.jmxremote.localConnectorAddress", null);
if(null == GlobalVariables.connectorAddress) {
    // It's not, so install the management agent
    String javaHome = GlobalVariables.vm.getSystemProperties().getProperty("java.home");
    File managementAgentJarFile = new File(javaHome + File.separator + "lib" + File.separator + "management-agent.jar");
    GlobalVariables.vm.loadAgent(managementAgentJarFile.getAbsolutePath());
    System.out.println("Load Management agent");
    GlobalVariables.connectorAddress = GlobalVariables.vm.getAgentProperties().getProperty("com.sun.management.jmxremote.localConnectorAddress", null);
    // Now it's installed
}

// Now connect and transform the classnames provided in the remaining args.
//JMXConnector connector = null;
try {
    // This is the ObjectName of the MBean registered when loaded.jar was installed.
    //ObjectName on = new ObjectName("transformer:service=DemoTransformer");
    GlobalVariables.on = new ObjectName("transformer:service=DemoTransformer");
    // Here we're connecting to the target JVM through the management agent
    GlobalVariables.connector = JMXConnectorFactory.connect(new JMXServiceURL(GlobalVariables.connectorAddress));
    GlobalVariables.server = GlobalVariables.connector.getMBeanServerConnection();
    System.out.println("MBean Server connection...");

    // Call transformClass on the transformer MBean
    GlobalVariables.server.invoke(GlobalVariables.on, "transformClass", new Object[]{className, args}, new String[]{String.class.getName(), String.class.getName()});

} catch (Exception ex) {
    ex.printStackTrace(System.err);
} finally {
    if(GlobalVariables.connector!=null) try { GlobalVariables.connector.close(); } catch (Exception e) {}
    GlobalVariables.vm.detach();
    System.out.println("Has disconnected");
}

那我做了什么

我再次运行上述代码以再次加载这两个代理。但我遇到了错误。

错误

当前虚拟机出错

com.sun.tools.attach.AgentInitializationException: Agent JAR loaded but agent failed to initialize
    at sun.tools.attach.HotSpotVirtualMachine.loadAgent(HotSpotVirtualMachine.java:103)
    at com.sun.tools.attach.VirtualMachine.loadAgent(VirtualMachine.java:508)
    at faultinjectionaction.AttachClass.attachAgent(AttachClass.java:111)
    at org.apache.jsp.fjstep3_jsp._jspService(fjstep3_jsp.java:350)
    at org.apache.jasper.runtime.HttpJspBase.service(HttpJspBase.java:70)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:728)
    at org.apache.jasper.servlet.JspServletWrapper.service(JspServletWrapper.java:432)
    at org.apache.jasper.servlet.JspServlet.serviceJspFile(JspServlet.java:390)
    at org.apache.jasper.servlet.JspServlet.service(JspServlet.java:334)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:728)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:305)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:222)
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:123)
    at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:502)
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:171)
    at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:99)
    at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:953)
    at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:118)
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:408)
    at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1023)
    at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:589)
    at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:310)
    at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908)
    at java.lang.Thread.run(Thread.java:619)

目标虚拟机出错

Exception in thread "Attach Listener" java.lang.reflect.InvocationTargetException
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
        at java.lang.reflect.Method.invoke(Method.java:597)
        at sun.instrument.InstrumentationImpl.loadClassAndStartAgent(InstrumentationImpl.java:323)
        at sun.instrument.InstrumentationImpl.loadClassAndCallAgentmain(InstrumentationImpl.java:348)
Caused by: javax.management.InstanceAlreadyExistsException: transformer:service= DemoTransformer
        at com.sun.jmx.mbeanserver.Repository.addMBean(Repository.java:453)
        at com.sun.jmx.interceptor.DefaultMBeanServerInterceptor.internal_addObject(DefaultMBeanServerInterceptor.java:1484)
        at com.sun.jmx.interceptor.DefaultMBeanServerInterceptor.registerDynamicMBean(DefaultMBeanServerInterceptor.java:963)
        at com.sun.jmx.interceptor.DefaultMBeanServerInterceptor.registerObject(DefaultMBeanServerInterceptor.java:917)
        at com.sun.jmx.interceptor.DefaultMBeanServerInterceptor.registerMBean(DefaultMBeanServerInterceptor.java:312)
        at com.sun.jmx.mbeanserver.JmxMBeanServer.registerMBean(JmxMBeanServer.java:482)
        at faultinjectionagent.AgentMain.agentmain(AgentMain.java:28)
        ... 6 more

瞄准

做同样的工作没有错误。我想我每次完成工作后都需要卸下代理。但是我没有卸载那些代理。

编辑 GlobleVariables

import javax.management.MBeanServerConnection;
import javax.management.ObjectName;
import javax.management.remote.JMXConnector;
import com.sun.tools.attach.VirtualMachine;

public class GlobalVariables{
    public static MBeanServerConnection server;
    public static ObjectName on;
    public static JMXConnector connector = null;
    public static String connectorAddress = null;
    public static VirtualMachine vm;
}

【问题讨论】:

  • 你的代码的第一行漏掉了一个点,我想? GlobalVariables.vm = VirtualMachine.attach(vid);
  • 在这里复制我的代码时丢失了。这是我计划的一部分。

标签: jboss aop agent cglib javaagents


【解决方案1】:

卸载代理是什么意思?您无法卸载文档中隐含的类:

指定的 JAR 文件被添加到系统类路径(的 目标虚拟机)

解决这个问题的唯一方法可能是一些自定义类加载器魔法,但我不建议这样做。

更新:在查看了您的扩展问题后,我认为您的问题实际上是其他问题。在某些时候你正在调用

JMXConnectorFactory.connect(new JMXServiceURL(GlobalVariables.connectorAddress))

为了创建一个JMXConnector。我猜在您的GlobalVariables.server.invoke 调用中,您正在通过new ObjectName("transformer:service=DemoTransformer") 注册一个MBean。此名称必须是唯一的,并且当您第二次运行代码时,此名称已按照javax.management.InstanceAlreadyExistsException: transformer:service= DemoTransformer 的建议使用。你需要做的是:

  • 第二次注册 MBean 时选择其他名称。
  • 在从远程 JVM 分离之前调用 MBeanServerConnection.close(new ObjectName("transformer:service=DemoTransformer")) 以使名称再次可用。

您可能假设通过分离,远程计算机上的所有状态都已重置。然而,这不是真的。您添加了一个具有名称的 MBean,然后您再次尝试执行此操作。这个错误可以理解为好像你在一个映射中添加了一个具有相同键的两个值。但是,除了地图之外,您不会覆盖值,而是会导致您在上面观察到的异常。

顺便说一句:当不再需要与远程服务器的连接时,您应该显式调用JMXConnector.close。

PS:你可能会觉得this article很有趣。

更新 2:在聊天中讨论并解决 MBean 命名冲突之后,我认为这是导致问题的原因:

当第二次加载 Java 代理时,代理附带的类(以managementAgentJarFile 表示)已经加载到目标 JVM 中。这意味着,不会再次运行任何类初始化程序,并且由static 变量表示的状态更改仍将被表示。此外,无法加载具有相同名称但更改了实现的类。这将导致LinkageErrors 并且代理加载将失败。解决方案是避免static 状态,以使代理无法影响自己,并为不同的代理创建单独的名称空间。否则,可以使用自定义类加载器卸载代理类。可以在许多地方和此处找到有关此问题的更多信息:

【讨论】:

  • remove an Instrumentation 是否意味着unload agent?
  • 我已经编辑了我的问题@raphw。你能帮我提些建议吗?谢谢
  • GlobalVariables 的超类型VirtualMachine 是什么?这甚至不应该编译。
  • 一个包含static的变量的类。我已将代码添加到我的问题描述中。 @raphw
  • 我想我明白你的问题是什么了。您注册了两个同名的 MBean。请参阅上面我编辑的答案。
猜你喜欢
  • 1970-01-01
  • 2012-07-08
  • 1970-01-01
  • 2015-09-20
  • 1970-01-01
  • 1970-01-01
  • 2013-06-26
  • 1970-01-01
  • 2019-06-20
相关资源
最近更新 更多