如何查找正在运行的JVM附加的Java代理列表?

9
我正在尝试调试添加到生产JVM中的一个Java代理的问题。
在应用程序启动脚本中,Java代理已经被正确添加,并且在其他环境中一直工作。但是在生产环境中,这个代理似乎没有起作用。
有没有办法找到已添加的Java代理列表?

我相信你做不到,可以看看这个答案https://dev59.com/QVnUa4cB1Zd3GeqPeNOY。你可以解析JVM参数`-javaagent`,但如果代理以不同的方式加载,你将无法找到它。 - SubOptimal
请查看@RRM下面的答案。 - Joe
2个回答

6

(这个问题类似于JVM能否通过Attach API检索已加载的代理程序列表?为了完整起见,我将在两个问题中都添加此答案。)


检查通过命令行添加的代理程序:

如果您对使用命令行界面添加的代理程序有兴趣,可以使用RuntimeMXBean来检查它们。

这个bean提供了getInputArguments方法,它返回所有VM参数的列表。您可以遍历列表,并检查它是否包含参数agentpathagentlibjavaagent,就像以下代码片段一样:

    RuntimeMXBean runtimeMXBean = ManagementFactory.getRuntimeMXBean();
    List<String> jvmArgs = runtimeMXBean.getInputArguments();
    System.out.println("JVM arguments:");
    for (String arg : jvmArgs) {
        if (arg.startsWith("-agentpath") || arg.startsWith("-agentlib") || arg.startsWith("-javaagent")) {
            System.out.print("***** ");
        }

        System.out.print(arg);

        if (arg.startsWith("-agentpath") || arg.startsWith("-agentlib") || arg.startsWith("-javaagent")) {
            System.out.println(" *****");
        } else {
            System.out.println();
        }
    }

检查使用Attach API添加的代理:

如果您对在运行时使用Attach API添加到应用程序中的代理感兴趣,您可以使用DiagnosticCommandMBean。 此bean提供了一个名为vmDynlib的诊断命令,它是一个无参数方法,返回一个String,其中列出所有动态加载的库。

这里是一个代码片段,打印应用程序VM加载的所有动态库:

ObjectName diagnosticsCommandName = new ObjectName("com.sun.management:type=DiagnosticCommand");
String operationName = "vmDynlibs";
String result = (String) ManagementFactory.getPlatformMBeanServer().invoke(diagnosticsCommandName, operationName, null, null);
System.out.println(result);

这会导致类似于下面的输出结果:
Dynamic libraries:
0x00007ff7b8600000 - 0x00007ff7b8637000     C:\Program Files\Java\jdk1.8.0_181\bin\java.exe
0x00007ffdfeb00000 - 0x00007ffdfecf0000     C:\WINDOWS\SYSTEM32\ntdll.dll
0x00007ffdfe300000 - 0x00007ffdfe3b2000     C:\WINDOWS\System32\KERNEL32.DLL
0x00007ffdfbb30000 - 0x00007ffdfbdd3000     C:\WINDOWS\System32\KERNELBASE.dll
0x00007ffdfe950000 - 0x00007ffdfe9f3000     C:\WINDOWS\System32\ADVAPI32.dll
...

接下来您可以检查此文本中是否包含某个.so.dll文件。


同样的检查也可以非编程方式执行。

为此,您可以使用jconsole工具。

连接到虚拟机,切换到选项卡MBeans,选择com.sun.management,选择DiagnosticCommand,选择Operations,选择vmDynlibs,并调用它。

vmDynlibs output

在图像中,您可以看到我测试代理程序之一连接到应用程序。 代理程序是使用Attach API附加的,因此通过检查应用程序的命令行参数不会看到-agentpath=...(即不会在参数上看到),但只能作为动态加载库显示。


1
你可以使用额外的指定代理(使用premain附加)列出所有其他代理。 这个代理必须是启动生产JVM的java命令列表中的第一个。
每当添加任何类时,请检查它是否具有agentmain(String,Instrumentation)或premain(String,Instrumentation)签名方法。如果是,则有一个代理匹配。

不错的技巧。我刚想到了类似的东西,不过这似乎在资源方面是一个更好的想法。 - Joe
我很可能会将这个放到生产环境中,以及最佳答案。只是想让你知道。 - jado

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接