是否有一种简单的方法可以在Java中获取特定类的所有对象实例

Mir*_*ahn 17 java profiling jvm

目前我正在使用Java代理来组装内存统计信息.在instrumentation API的帮助下,我可以获得类(并操纵它们).使用普通Java,我可以估计每个对象使用的资源.到现在为止还挺好.

我现在面临的问题是"如何掌握特定类的每个Object实例".我可以进行字节代码操作以获取对象实例,但我希望有另一个我不知道的API,帮助我实现我的目标,没有这么大的侵入性步骤.最后,应将性能影响保持在最低限度.有任何想法吗?

Eli*_*kan 21

Eclipse中的调试器可以向您显示类的所有实例,因此我查看了Eclipse的源代码.Eclipse使用Java Debug Wire Protocol,它允许您(从Java 6开始)查找所请求类的所有实例.如果您想沿着这条路走下去,请获取Eclipse源代码的副本并查看instances方法org.eclipse.jdi.internal.ReferenceTypeImpl.

一种更简单的方法是使用Java调试接口.注意ReferenceType.instances方法.

我还没有弄清楚如何使用JDI连接到正在运行的进程以及如何获取实例ReferenceType.JDK包含几个例子,所以我确信它是可行的.


Dmi*_*y.M 5

正如其他答案中所解释的,您可以使用 JDI 协议来做到这一点。这很简单:您需要使用以下命令在调试模式下运行 JVM

--agentlib:jdwp=传输=dt_socket,服务器=y,挂起=n,地址=56855

之后,您可以连接到远程(或本地 JVM)并列出指定类的所有实例。此外,您不能直接将远程对象转换为真实对象,但您可以访问远程对象的所有字段,甚至是 cal 方法。

这里介绍如何连接到远程 JVM 并获取VirtualMachine

    private static VirtualMachine attach(String hostname, String port) throws IOException, IllegalConnectorArgumentsException {
        //getSocketAttaching connector to connect to other JVM using Socket
        AttachingConnector connector = Bootstrap.virtualMachineManager().attachingConnectors()
                .stream().filter(p -> p.transport().name().contains("socket"))
                .findFirst().get();

        //set the arguments for the connector
        Map<String, Argument> arg = connector.defaultArguments();
        arg.get("hostname").setValue(hostname);
        arg.get("port").setValue(port);

        //connect to remote process by socket
        return connector.attach(arg);
    }
Run Code Online (Sandbox Code Playgroud)

获得VirtualMachine 后,您可以使用classesByName 和instances 方法获取类的实例。它返回ReferenceType的列表:

         VirtualMachine vm = attach("localhost", "56856");

        //get all classes of java.lang.String. There would be only one element.
        List<ReferenceType> classes = vm.classesByName("java.lang.String");

        //get all instances of a classes (set maximum count of instannces to get).
        List<ObjectReference> o = classes.get(0).instances(100000);

        //objectReference holds referenct to remote object. 
        for (ObjectReference objectReference : o) {
            try {
                //show text representation of remote object
                System.out.println(objectReference.toString());
            } catch (com.sun.jdi.ObjectCollectedException e) {
                //the specified object has been garbage collected
                //to avoid this use vm.suspend() vm.resume()
                System.out.println(e);
            }
        }
Run Code Online (Sandbox Code Playgroud)

这是一个程序的工作示例,该程序运行并连接到自身并列出 java.lang.String 的所有实例。要运行示例,您需要类路径中 jdk 中的 tool.jar。