Accurate object size measurement

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); } } 
+6
source share
2 answers

Since links have 8 bytes on a 64-bit JVM

This is your potentially erroneous assumption.

HotSpot can use "compressed oops" to use 32-bit values ​​for links in some places in the JVM (highlighted mine):

What compression are compressed?

In the JVM in ILP32 mode, or if the UseCompressedOops flag is disabled in LP64 mode, all oops is the native size of the machine word.

If UseCompressedOops is true, the following heap compressions will be compressed:

  • klass field of each object
  • each oop instance field
  • each element of the oop array (objArray)

I suspect this is happening in your case.

Test it using

 -XX:-UseCompressedOops 

or

 -XX:+UseCompressedOops 

On my machine, by default I get the same results as you, but with -XX:-UseCompressedOops I see:

 Object:16 bytes Object with 1 int:24 bytes Object with 2 ints:24 bytes Object with 3 ints:32 bytes Object with 1 long:24 bytes Object with 2 longs:32 bytes Object with 3 longs:40 bytes Object with 1 reference:24 bytes Object with 2 references:32 bytes Object with 3 references:40 bytes 

... which is probably closer to the expected :)

+5
source

The size of a Java object is known when the class is defined.

Java Object Memory Usage: General http://www.javamex.com/tutorials/memory/object_memory_usage.shtml

0
source

All Articles