Calculate size of Object in Java

JavaMemoryMemory ManagementData Structures

Java Problem Overview


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!

Java Solutions


Solution 1 - Java

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

Solution 2 - Java

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));
  }
}

Solution 3 - Java

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() { }
}

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionTyler PetrochkoView Question on Stackoverflow
Solution 1 - JavaHunter McMillenView Answer on Stackoverflow
Solution 2 - JavaLouis WassermanView Answer on Stackoverflow
Solution 3 - JavaMiguel GamboaView Answer on Stackoverflow