Wednesday, March 28, 2012

Counting number of Objects in Java

Dear reader,
I am writing a very common use case here: Counting number of objects which are there in HEAP memory.
This is basically an interview question: how to count number of objects created for a class.

Giving a very basic example below:
=================
public class MySerialization1 {
    static int counter;    //Defined a counter for this class
    static String className="MySerialization1"; 
    
    public MySerialization1() {
        synchronized(MySerialization.class) {   //making the counter thread safe
            counter++;
        }
    }
    public static void main(String args[]) throws Exception {
        MySerialization1 oc = new MySerialization1();  
        MySerialization1 od = new MySerialization1();
        MySerialization1 oe = new MySerialization1();
        MySerialization1 of = new MySerialization1();
        MySerialization1 og = new MySerialization1();
        System.out.println("Total object count: "+counter);

        Object ob=Class.forName(className).newInstance();  //Creating object using Class.forName();
        System.out.println("Total object count after Class.forName().newInstance(): "+counter);
        
        og.makeNull();    //Decrease the counter value
        og=null;          //Make object null       
        System.out.println("Total object count after null: "+counter);
    }
    private static void makeNull() {
        synchronized(MySerialization.class) {
            counter--;
        }
    }
}
//Output:
Total object count: 5
Total object count after Class.forName().newInstance(): 6
Total object count after null: 5
===================

Now, lets tweak little bit. When you serialize, you will have an object. What if you de-serialize here,
since constructor didn't get invoked at de-serialization time(assuming no inheritance here), you will have 
the same count of object. I mean see below example:

===================
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;

public class MySerialization implements Serializable {
    private static final long serialVersionUID = 1L;
    static String className="MySerialization"; 
    static int counter;
    public MySerialization(){
        synchronized(MySerialization.class) {
            counter++;
        }
    }

    public static void main(String[] args) throws Exception {
        MySerialization object=new MySerialization();
        System.out.println("Object is: "+object);
        ObjectOutputStream out=new ObjectOutputStream(new FileOutputStream("output.out"));
        out.writeObject(object);
        System.out.println("Object is saved using Serialization");

        ObjectInputStream in=new ObjectInputStream(new FileInputStream("output.out"));
        MySerialization deserialObject=(MySerialization)(in.readObject());
        System.out.println("Object is read using De-Serialization");
        System.out.println("Object is: "+deserialObject);
        System.out.println("Total object count after deserialization: "+counter);

        Object tempObj=Class.forName(className).newInstance();
        System.out.println("Total object count after Class.forName().newInstance(): "+counter);
    }

    //Comment the below method and then see the output again, This is read internally
    //while de-serializing object by JVM.
    /*
    private Object readResolve(){
        return new MySerialization();
    }
    */
}

//Output: 
Object is: MySerialization@1c4bd0
Object is saved using Serialization
Object is read using De-Serialization
Object is: MySerialization@1c68b0
Total object count after deserialization: 1
Total object count after Class.forName().newInstance(): 2

NOTE: If you see the output, after de-serialization too, count is only 1. Count is increased to "2"
      because of Class.forName().newInstance().
      Now un-comment the comment line, having method "readResolve()" and then run the same program, 
      below is the output:

//Output:
Object is: MySerialization@1c4bd0
Object is saved using Serialization
Object is read using De-Serialization
Object is: MySerialization@1c68c8
Total object count after deserialization: 2
Total object count after Class.forName().newInstance(): 3

NOTE: See the difference. When Java De-Serializes a saved object, it checks whether "readResolve()" 
      method is re-defined in Serializable class or no. You can use "public" access specifier too in place
      of "private". If re-defined, it return the object from there. Since constructor again gets called,
      Counter is increased. 
      The same logic we use in SingletonPattern too, where even after De-Serialization, we need the same 
      old object (I mean only one object) else De-serialization creates a new/converted one which violates 
      Singleton Pattern fundamental.

NOTE: A more sophisticated program which will show count of Objects of each class used in Program will be written
      later, as I have not written as of now. 
      Like if we use Thread, StringBuffer, HashMap, List etc in our program and then there should be a method to 
      display ObjectStatistics for each class used in program. You can use Inner class and put a counter there.
      I will write later.      
      
--------------------------------END--------------------------------      

No comments:

Post a Comment