The code at the bottom of this question is a bit long, but basically it creates several objects and determines their size in memory. I am executing the code with the following JVM parameters (TLAB to avoid memory allocation and possibly get accurate memory usage data):
-server -Xms2000m -Xmx2000m -verbose:gc -XX:-UseTLAB
I run the code in the 64-bit JVM Hotspot and get the following output:
HotSpot (TM) 64-bit Java Server Virtual Machine
Object: 16 bytes
Object with 1 int: 16 bytes
Object with 2 ints: 24 bytes
Object with 3 targets: 24 bytes
Object with 1 length: 24 bytes
Object with two lengths: 32 bytes
Object with 3 lengths: 40 bytes
Object with 1 reference: 16 bytes
Object with 2 links: 24 bytes
Object with 3 links: 24 bytes
I conclude that:
- the object accepts 12 bytes, aligned to 16 bytes.
- int takes 4 bytes (1 object with one int is 12 + 4 = still 16 bytes, with 2 ints: 12 + 8 = 20 aligned with 24 bytes)
- long takes 8 bytes (1 object with one long 12 + 8 = 20 bytes, aligned to 24 bytes)
But I do not understand why links do not use as much space as long s.
Since links have 8 bytes on a 64-bit JVM, the obvious conclusion is that the measurement methodology has a drawback *. Can you explain what is happening and what can be done to fix it?
<sub> * Note: sub>
- GC is not performed during measurement.
- Using Netbeans Profiler gives similar results.
public class TestMemoryReference { private static final int SIZE = 100_000; private static Runnable r; private static Object o = new Object(); private static Object o1 = new Object(); private static Object o2 = new Object(); private static Object o3 = new Object(); public static class ObjectWith1Int { int i; } public static class ObjectWith2Ints { int i, j; } public static class ObjectWith3Ints { int i, j, k; } public static class ObjectWith1Long { long i; } public static class ObjectWith2Longs { long i, j; } public static class ObjectWith3Longs { long i, j, k; } public static class ObjectWith1Object { Object o = o1; } public static class ObjectWith2Objects { Object o = o1; Object p = o2; } public static class ObjectWith3Objects { Object o = o1; Object p = o2; Object q = o3; } private static void test(Runnable r, String name, int numberOfObjects) { long mem = Runtime.getRuntime().freeMemory(); r.run(); System.out.println(name + ":" + (mem - Runtime.getRuntime().freeMemory()) / numberOfObjects + " bytes "); } public static void main(String[] args) throws Exception { System.out.println(System.getProperty("java.vm.name") + " "); r = new Runnable() { public void run() { for (int i = 0; i < SIZE; i++) o = new Object(); } }; test(r, "Object", SIZE); r = new Runnable() { public void run() { for (int i = 0; i < SIZE; i++) o = new ObjectWith1Int(); } }; test(r, "Object with 1 int", SIZE); r = new Runnable() { public void run() { for (int i = 0; i < SIZE; i++) o = new ObjectWith2Ints(); } }; test(r, "Object with 2 ints", SIZE); r = new Runnable() { public void run() { for (int i = 0; i < SIZE; i++) o = new ObjectWith3Ints(); } }; test(r, "Object with 3 ints", SIZE); r = new Runnable() { public void run() { for (int i = 0; i < SIZE; i++) o = new ObjectWith1Long(); } }; test(r, "Object with 1 long", SIZE); r = new Runnable() { public void run() { for (int i = 0; i < SIZE; i++) o = new ObjectWith2Longs(); } }; test(r, "Object with 2 longs", SIZE); r = new Runnable() { public void run() { for (int i = 0; i < SIZE; i++) o = new ObjectWith3Longs(); } }; test(r, "Object with 3 longs", SIZE); r = new Runnable() { public void run() { for (int i = 0; i < SIZE; i++) o = new ObjectWith1Object(); } }; test(r, "Object with 1 reference", SIZE); r = new Runnable() { public void run() { for (int i = 0; i < SIZE; i++) o = new ObjectWith2Objects(); } }; test(r, "Object with 2 references", SIZE); r = new Runnable() { public void run() { for (int i = 0; i < SIZE; i++) o = new ObjectWith3Objects(); } }; test(r, "Object with 3 references", SIZE); } }