In one of mine project work I was required to calculate the size of an object the best way that I found is this :
when I started r&d for this topic I came to know that in java 1.5 there is an api introduced i.e instrumentation agent by using that we have a premain method which is called by the JVM even before the void main. so by storing the information of objects in jvm and then calculating the size was the core concept to know the memory utilization of an object. I know theortically it is very easy to write. Well I wont disappoint you .. practically as well :) here is the step by step approach to calculate the memory consumed by an object in your application :
First thing that is required is to have a class in your project which contains premain method the sample class is shown below:-
package com.memory;
import java.lang.instrument.Instrumentation;
public class MyAgent { static Instrumentation inst; /** initializes agent */ public static void premain(String agentArgs, Instrumentation instP) { inst = instP; } }
Second thing to do is to keep in mind that this application has to be run on command prompt and you have to make a jar of your project which will be having above mentioned class. class name and package are your choices.
While making jar of your project you have to write this line (Premain-Class: ****.rc.postpay.controller.MyAgent) in your manifest file. This is mandatory the class name and package name varies according to your comfort and requirement.
well half of the work is done now next task is to recusively calculate the size . For that use the code shown below:
/** * Returns object size without member sub-objects. * @param o object to get size of * @return object size */ public static long sizeOf(Object o) { if(inst == null) { throw new IllegalStateException("Can not access instrumentation environment.\n" + "Please check if jar file containing SizeOfAgent class is \n" + "specified in the java's \"-javaagent\" command line argument."); } return inst.getObjectSize(o); } /** * Calculates full size of object iterating over * its hierarchy graph. * @param obj object to calculate size of * @return object size */ public static long fullSizeOf(Object obj) { Map Stack stack = new Stack();
long result = internalSizeOf(obj, stack, visited); while (!stack.isEmpty()) { result += internalSizeOf(stack.pop(), stack, visited); } visited.clear(); return result; } private static boolean skipObject(Object obj, Map visited) { if (obj instanceof String) { // skip interned string if (obj == ((String) obj).intern()) { return true; } } return (obj == null) // skip visited object || visited.containsKey(obj); } private static long internalSizeOf(Object obj, Stack stack, Map visited) {
if (skipObject(obj, visited)){ return 0; } visited.put(obj, null); long result = 0; // get size of object + primitive variables + member pointers result += MyAgent.sizeOf(obj); // process all array elements Class clazz = obj.getClass(); if (clazz.isArray()) { if(clazz.getName().length() != 2) {// skip primitive type array int length = Array.getLength(obj); for (int i = 0; i < length; i++) { stack.add(Array.get(obj, i)); } } return result; } // process all fields of the object while (clazz != null) { Field[] fields = clazz.getDeclaredFields(); for (int i = 0; i < fields.length; i++) { if (!Modifier.isStatic(fields[i].getModifiers())) { if (fields[i].getType().isPrimitive()) { continue; // skip primitive fields } else { fields[i].setAccessible(true); try { // objects to be estimated are put to stack Object objectToAdd = fields[i].get(obj); if (objectToAdd != null) { stack.add(objectToAdd); } } catch (IllegalAccessException ex) { assert false; } } } } clazz = clazz.getSuperclass(); } return result; } }
Put all these methods in MyAgent class as these methods needs the instance of Intrumentation agent.Call the method [ MyAgent.fullSizeOf(o);] where o is an object for whom every one is concerned.
to write in a file or to print on the console you can write custom methods like the one shown below.
You can call this below mentioned method wherever you need to know the size of your object and this method will print the size on console and write in file as well.
public static void measureSize(Object o, String filename) { System.out.println("inside measure size"); long sizeInBytes = MyAgent.fullSizeOf(o); double sizeInKB = (sizeInBytes / 1024); double sizeInMB = (sizeInKB / 1024); try { // Create file FileWriter fstream = new FileWriter("c://MemoryUsageForReferenceData", true); BufferedWriter out = new BufferedWriter(fstream); out.write(filename + "," + sizeInKB + "," + sizeInMB +"\n"); // Close the output stream out.close(); } catch (Exception e) {// Catch exception if any System.err.println("Error: " + e.getMessage()); } // long size = MyAgent.getObjectSize(o); /* * System.out.printf("size =%d", size); */ // int mapSize = o.size(); // System.out.println("map size" + mapSize); System.out.println("size --- " + sizeInKB); }
Well we are almost done . The only thing remaining is to run this application on command prompt.
Firstly I will summarize then we will run. Make one class Like My Agent put all the methods which are shown below put this class in your project and make the jar having manifest file which contains [Premain-Class: uk.co.o2.rc.postpay.controller.MyAgent] package and class name depends on you premain-class is mandatory dont play with that.
Thats it we are done now open your command prompt and run your jar by this command.
Set all the classpath that you need for your project . Then execute this command
java - javaagent:[yourJar name] [the class name which contains the main Method]
for example :
java -javaagent:c:/memoryAgent.jar com.memoryagent.Test
Done :)
please post queries for anything confusing/wrong
No comments:
Post a Comment