【问题标题】:Is there a simple way of obtaining all object instances of a specific class in Java是否有一种简单的方法可以在 Java 中获取特定类的所有对象实例
【发布时间】:2010-12-29 03:52:10
【问题描述】:

目前我正在开发一个 Java 代理来组装内存统计信息。在instrumentation API 的帮助下,我可以掌握课程(并操纵它们)。使用纯 Java,我可以估计每个对象使用的资源。到目前为止,一切顺利。

我现在面临的问题是“如何获取特定类的每个 Object 实例”。我可以进行字节码操作以获取对象实例,但我希望有另一个我不知道的 API,帮助我在没有如此繁重的侵入步骤的情况下完成我的目标。最后,应将性能影响降至最低。有什么想法吗?

【问题讨论】:

    标签: java jvm profiling


    【解决方案1】:

    根据我在之前的帖子中了解到的情况,无法获取 Java 中类的所有实例的列表。反射 API 做了一些简洁的事情,但不是这个特定的事情。

    你能做的最好的事情是持有指向所有对象的指针,但这看起来很淫秽,并且不适用于其他人的程序。不太理想吧?

    【讨论】:

    【解决方案2】:

    当我读到这篇文章时,我在想必须有某种方法来获取这种信息,因为存在 java 分析器。也许这会有所帮助:http://java.sun.com/j2se/1.4.2/docs/guide/jvmpi/jvmpi.html。它描述了 JVM 和分析器代理之间的接口。但如果你真的想用 Java 写这个,那你可能就不走运了。

    具体来说,看看这个函数:

    jint (*EnableEvent)(jint event_type, void *arg);
    
        Called by the profiler agent to enable notification of a particular type of event. Apart from event_type, the profiler may also pass an argument that provides additional information specific to the given event type.
    
        All events are disabled when the VM starts up. Once enabled, an event stays enabled until it is explicitly disabled.
    
        This function returns JVMPI_NOT_AVAILABLE if event_type is JVMPI_EVENT_HEAP_DUMP, JVMPI_EVENT_MONITOR_DUMP or JVMPI_EVENT_OBJECT_DUMP. The profiler agent must use the RequestEvent function to request these events.
    
        Arguments:
    
            event_type  - type of event, JVMPI_EVENT_CLASS_LOAD etc.
            arg     - event specific argument.
    
        Returns:
    
            JVMPI_SUCCESS   enable succeeded.
            JVMPI_FAIL  enable failed.
            JVMPI_NOT_AVAILABLE     support for enabling the given event_type is not available. 
    

    【讨论】:

    【解决方案3】:

    Eclipse 中的调试器可以show you all the instances of a class,所以我查看了 Eclipse 的源码。 Eclipse 使用Java Debug Wire Protocol,它允许您(从Java 6 开始)查找所请求类的所有实例。如果您想走这条路,请获取 Eclipse 源代码的副本并查看 org.eclipse.jdi.internal.ReferenceTypeImplinstances 方法。

    更简单的方法是使用Java Debug Interface。注意ReferenceType.instances 方法。

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

    【讨论】:

      【解决方案4】:

      http://java.sun.com/j2se/1.5.0/docs/guide/jvmti/jvmti.html#IterateOverInstancesOfClass

      您可以编写一些获取 JVMTI 指针的本机代码,然后使用它来 遍历给定类的所有实例,如上面的链接所示。 您可以从 Java 程序中调用此本地代码。 正如 Eli 指出的那样,从 Java 6 开始,有一个称为 Java 调试接口的高级包装器,它允许您从 Java 本身进行此类调用,而无需使用本机代码。

      希望对你有帮助

      内存

      【讨论】:

        【解决方案5】:

        我想知道您是否可以使用BTrace 来完成您正在尝试做的事情?

        【讨论】:

          【解决方案6】:

          正如其他答案中所解释的,您可以使用 JDI 协议来做到这一点。这相当简单:您需要使用

          在调试模式下运行 JVM

          --agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=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);
              }
          

          获取 VirtualMachine 后,您可以使用方法 classesByName 和实例获取类的实例。它返回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);
                      }
                  }
          

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

          【讨论】:

            猜你喜欢
            • 2017-07-05
            • 2017-02-19
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2013-08-25
            • 2011-03-02
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多