Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is there a simple way of obtaining all object instances of a specific class in Java

Currently I am working on a Java agent to assemble memory stats. With the help of the instrumentation API I can get a hold of the classes (and manipulate them). With plain Java I can get an estimate of the resources used for each object. So far, so good.

The question I am faced with right now is "how to get a hold of every Object instance of a specific class". I can do byte code manipulation in order to get a hold of the object instance, but I was hoping there is another API I am not aware of, helping me to accomplish my goal without such a rather heavy intrusive step. At the end, the performance impact should be kept to a minimum. Any ideas?

like image 254
Mirko Jahn Avatar asked Dec 22 '09 15:12

Mirko Jahn


People also ask

How do I get all the instances of a class?

To print all instances of a class with Python, we can use the gc module. We have the A class and we create 2 instances of it, which we assigned to a1 and a2 . Then we loop through the objects in memory with gc. get_objects with a for loop.

How do you check if an object is an instance of a particular class Java?

The java “instanceof” operator is used to test whether the object is an instance of the specified type (class or subclass or interface). It is also known as type comparison operator because it compares the instance with type. It returns either true or false.

How many ways we can get the instance of class class?

In Java, we can create objects with 6 different methods which are: By new keyword. By newInstance() method of Class class. By newInstance() method of constructor class.

How do I find the instance of a class in Java?

The instanceof operator in Java is used to check whether an object is an instance of a particular class or not. objectName instanceOf className; Here, if objectName is an instance of className , the operator returns true . Otherwise, it returns false .


5 Answers

The debugger in Eclipse can show you all the instances of a class, so I looked around Eclipse's sources. Eclipse uses the Java Debug Wire Protocol, which allows you (since Java 6) to look up all the instances of the requested class. If you want to go down this path, grab a copy of Eclipse sources and check out the instances method of org.eclipse.jdi.internal.ReferenceTypeImpl.

A simpler way is to use the Java Debug Interface. Note the ReferenceType.instances method.

I still haven't figured out how to use JDI to connect to a running process and how to obtain an instance of ReferenceType. The JDK contains several examples, so I'm sure it's doable.

like image 98
Eli Acherkan Avatar answered Oct 10 '22 16:10

Eli Acherkan


When I read this I was thinking that there must be SOME way to get this kind of info, since java profilers exist. Maybe this will help: http://java.sun.com/j2se/1.4.2/docs/guide/jvmpi/jvmpi.html. It describes the interface between the JVM and a profiler agent. But if you were actually looking to write this in Java you may be out of luck.

Specifically, check out this function:

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. 
like image 34
danben Avatar answered Oct 10 '22 17:10

danben


As explained in the other answers you can do it by using the JDI protocol. It is rather simple: you need to run the JVM in debug mode using

--agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=56855

after that, you can connect to the remote (or local JVM) and list all instances of the specified class. Also, you cannot directly cast remote objects to the real object but you can access to all the fields of the remote object and even cal methods.

Here how you can connect to remote JVM and get 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);
    }

After getting VirtualMachine you can get instances of a class using methods classesByName and instances. It return List of 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);
            }
        }

Here is a working example of a program than runs and connects to itself and list all instances of a java.lang.String. To run an example you need tool.jar from jdk in you classpath.

like image 23
Dmitry.M Avatar answered Oct 10 '22 15:10

Dmitry.M


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

You can write some native code that obtains the JVMTI pointer and then uses it to iterate over all instances of a given class as shown in the link above. You can call this native code from your Java program. As Eli points out though, there is a high level wrapper for this called Java Debug Interface available from Java 6 onwards, which allows you to make such calls from Java itself without having to muck around with native code.

hope this helps

Ram

like image 34
Ram Avatar answered Oct 10 '22 15:10

Ram


I wonder if what you are trying to do might be accomplished using BTrace?

like image 36
reidarok Avatar answered Oct 10 '22 16:10

reidarok