166
votes

I want to record how much memory (in bytes, hopefully) an object takes up for a project (I'm comparing sizes of data structures) and it seems like there is no method to do this in Java. Supposedly, C/C++ has sizeOf() method, but this is nonexistant in Java. I tried recording the free memory in the JVM with Runtime.getRuntime().freeMemory() before and after creating the object and then recording the difference, but it would only give 0 or 131304, and nothing in between, regardless of the number of elements in the structure. Help please!

3
You may want to try the totalMemory() and then freeMemory() and subtract those instead.Matt
I recommend you taking a look at Jbellis JAMM. (github.com/jbellis/jamm) It relies on the instrumentation agent mentioned above but encapsulates some hepful utilities to deep measure the footprint of an entire object-graph. Looks simple and pretty cool to me.Claudio

3 Answers

96
votes

You can use the java.lang.instrumentation package.

It has a method that can be used to get the implementation specific approximation of object size, as well as overhead associated with the object.

The answer that Sergey linked has a great example, which I'll repost here, but you should have already looked at from his comment:

import java.lang.instrument.Instrumentation;

public class ObjectSizeFetcher {
    private static Instrumentation instrumentation;

    public static void premain(String args, Instrumentation inst) {
        instrumentation = inst;
    }

    public static long getObjectSize(Object o) {
        return instrumentation.getObjectSize(o);
    }
}

Use getObjectSize:

public class C {
    private int x;
    private int y;

    public static void main(String [] args) {
        System.out.println(ObjectSizeFetcher.getObjectSize(new C()));
    }
}

Source

82
votes

Look into https://github.com/DimitrisAndreou/memory-measurer.
Guava uses it internally, and ObjectGraphMeasurer is especially straightforward to use out-of-the-box, without any special command-line arguments.

import objectexplorer.ObjectGraphMeasurer;

public class Measurer {

  public static void main(String[] args) {
    Set<Integer> hashset = new HashSet<Integer>();
    Random random = new Random();
    int n = 10000;
    for (int i = 1; i <= n; i++) {
      hashset.add(random.nextInt());
    }
    System.out.println(ObjectGraphMeasurer.measure(hashset));
  }
}
16
votes

The java.lang.instrument.Instrumentation class provides a nice way to get the size of a Java Object, but it requires you to define a premain and run your program with a java agent. This is very boring when you do not need any agent and then you have to provide a dummy Jar agent to your application.

So I got an alternative solution using the Unsafe class from the sun.misc. So, considering the objects heap alignment according to the processor architecture and calculating the maximum field offset, you can measure the size of a Java Object. In the example below I use an auxiliary class UtilUnsafe to get a reference to the sun.misc.Unsafe object.

private static final int NR_BITS = Integer.valueOf(System.getProperty("sun.arch.data.model"));
private static final int BYTE = 8;
private static final int WORD = NR_BITS/BYTE;
private static final int MIN_SIZE = 16; 

public static int sizeOf(Class src){
    //
    // Get the instance fields of src class
    // 
    List<Field> instanceFields = new LinkedList<Field>();
    do{
        if(src == Object.class) return MIN_SIZE;
        for (Field f : src.getDeclaredFields()) {
            if((f.getModifiers() & Modifier.STATIC) == 0){
                instanceFields.add(f);
            }
        }
        src = src.getSuperclass();
    }while(instanceFields.isEmpty());
    //
    // Get the field with the maximum offset
    //  
    long maxOffset = 0;
    for (Field f : instanceFields) {
        long offset = UtilUnsafe.UNSAFE.objectFieldOffset(f);
        if(offset > maxOffset) maxOffset = offset; 
    }
    return  (((int)maxOffset/WORD) + 1)*WORD; 
}
class UtilUnsafe {
    public static final sun.misc.Unsafe UNSAFE;

    static {
        Object theUnsafe = null;
        Exception exception = null;
        try {
            Class<?> uc = Class.forName("sun.misc.Unsafe");
            Field f = uc.getDeclaredField("theUnsafe");
            f.setAccessible(true);
            theUnsafe = f.get(uc);
        } catch (Exception e) { exception = e; }
        UNSAFE = (sun.misc.Unsafe) theUnsafe;
        if (UNSAFE == null) throw new Error("Could not obtain access to sun.misc.Unsafe", exception);
    }
    private UtilUnsafe() { }
}