Occasionally, you may be interested in measuring (or estimating) the size of an object in memory. Here's a utility which can help with that task, if the object's class has a no-argument constructor. It follows the style used by Java Platform Performance, by Wilson and Kesselman. Given a class name, it will build a number of objects using the no-argument constructor, and measure the effect on JVM memory use. Thus, it measures the size of 'empty' objects containing no data.
To measure the size of a particular object containing data, a similar technique can easily be used: measure JVM memory use before and after building the object.
In addition, JDK 1.5 has added an
Instrumentation
interface, which
includes a method named getObjectSize method.
However, this method seems to be intended for tool makers.
/** * Measures the approximate size of an object in memory, given a Class which * has a no-argument constructor. */ public final class ObjectSizer { /** * First and only argument is the package-qualified name of a class * which has a no-argument constructor. */ public static void main(String... aArguments){ Class theClass = null; try { theClass = Class.forName(aArguments[0]); } catch (Exception ex) { System.err.println("Cannot build a Class object: " + aArguments[0]); System.err.println("Use a package-qualified name, and check classpath."); } long size = ObjectSizer.getObjectSize( theClass ); System.out.println("Approximate size of " + theClass + " objects :" + size); } /** * Return the approximate size in bytes, and return zero if the class * has no default constructor. * * @param aClass refers to a class which has a no-argument constructor. */ public static long getObjectSize( Class aClass ){ long result = 0; //if the class does not have a no-argument constructor, then //inform the user and return 0. try { aClass.getConstructor( new Class[]{} ); } catch ( NoSuchMethodException ex ) { System.err.println(aClass + " does not have a no-argument constructor."); return result; } //this array will simply hold a bunch of references, such that //the objects cannot be garbage-collected Object[] objects = new Object[fSAMPLE_SIZE]; //build a bunch of identical objects try { Object throwAway = aClass.newInstance(); long startMemoryUse = getMemoryUse(); for (int idx=0; idx < objects.length ; ++idx) { objects[idx] = aClass.newInstance(); } long endMemoryUse = getMemoryUse(); float approximateSize = ( endMemoryUse - startMemoryUse ) /100f; result = Math.round( approximateSize ); } catch (Exception ex) { System.err.println("Cannot create object using " + aClass); } return result; } // PRIVATE // private static int fSAMPLE_SIZE = 100; private static long fSLEEP_INTERVAL = 100; private static long getMemoryUse(){ putOutTheGarbage(); long totalMemory = Runtime.getRuntime().totalMemory(); putOutTheGarbage(); long freeMemory = Runtime.getRuntime().freeMemory(); return (totalMemory - freeMemory); } private static void putOutTheGarbage() { collectGarbage(); collectGarbage(); } private static void collectGarbage() { try { System.gc(); Thread.currentThread().sleep(fSLEEP_INTERVAL); System.runFinalization(); Thread.currentThread().sleep(fSLEEP_INTERVAL); } catch (InterruptedException ex){ ex.printStackTrace(); } } }
ObjectSizer can be easily placed in an interactive console application.
An example run gives :
>java -cp . Console ObjectSizeInterpreter
Please enter a class name>java.blah
Invalid. Example:"java.lang.String">java.util.ArrayList
Approximate size of class java.util.ArrayList objects in bytes:
80
Please enter a class name>java.util.Vector
Approximate size of class java.util.Vector objects in bytes: 80
Please enter a class name>java.util.HashMap
Approximate size of class java.util.HashMap objects in bytes: 104
Please enter a class name>java.lang.Long
class java.lang.Long does not have a no-argument constructor.
Please enter a class name>exit
Bye.
Here is the Interpreter class :
import java.util.*; import java.text.MessageFormat; /** * Given a package-qualified class name, return the approximate size of * the object in bytes. */ public final class ObjectSizeInterpreter implements Interpreter { /** * @param aLine is a non-null, package-qualified name of a class. * @param aResult is a non-null, empty List which acts as an "out" * parameter; when returned, aResult must contain a non-null, non-empty * List containing a description of the size of the object. * * @return true only if the user has requested to quit the Interpreter. * @exception IllegalArgumentException if a param does not comply. */ public boolean parseInput (String aLine, final List aResult) { if ( aResult == null ) { throw new IllegalArgumentException("Result param cannot be null."); } if ( !aResult.isEmpty() ){ throw new IllegalArgumentException("Result param must be empty."); } if ( aLine == null ) { throw new IllegalArgumentException("Line must not be null."); } boolean hasRequestedQuit = aLine.trim().equalsIgnoreCase(fQUIT) || aLine.trim().equalsIgnoreCase(fEXIT); if ( hasRequestedQuit ) { //display only a blank line aResult.add(fNEW_LINE); } else { try { Class theClass = Class.forName(aLine); long size = ObjectSizer.getObjectSize( theClass ); if ( size > 0 ){ Object[] insertedData = {theClass, new Long(size) }; MessageFormat sizeMessage = new MessageFormat(fPATTERN); String message = sizeMessage.format( insertedData ); aResult.add( message ); aResult.add( fNEW_LINE ); } aResult.add( fDEFAULT_PROMPT ); } catch (ClassNotFoundException ex){ //recover by asking the user for corrected input aResult.clear(); aResult.add(fERROR_PROMPT); } } if ( aResult.isEmpty() ) { throw new IllegalStateException("Result must be non-empty."); } return hasRequestedQuit; } /** * Return the text to be displayed upon start-up of the Interpreter. */ public String getHelloPrompt() { return fHELLO_PROMPT; } /// PRIVATE ///// private static final String fHELLO_PROMPT = "Please enter a class name>"; private static final String fDEFAULT_PROMPT = "Please enter a class name>"; private static final String fERROR_PROMPT = "Invalid. Example:\"java.lang.String\">"; private static final String fPATTERN = "Approximate size of {0} objects in bytes: {1}"; private static final String fQUIT = "quit"; private static final String fEXIT = "exit"; private static final String fNEW_LINE = System.getProperty("line.separator"); }
|
|