Monday, December 15, 2008

How much memory is used by my Java object?

There's currently some buzz around the size of certain Java objects (Update: more on this below). Here is some very good description of what you have to take into account to compute the (shallow) size of an java object.
I repost here the rules from my old blog at SDN, because I think they are a more compact description of the memory usage for java objects.

The general rules for computing the size of an object on the SUN/SAP VM are :

32 bit

Arrays of boolean, byte, char, short, int: 2 * 4 (Object header) + 4 (length-field) + sizeof(primitiveType) * length -> align result up to a multiple of 8

Arrays of objects: 2 * 4 (Object header) + 4 (length-field) + 4 * length -> align result up to a multiple of 8

Arrays of longs and doubles: 2 * 4 (Object header) + 4 (length-field) + 4 (dead space due to alignment restrictions) + 8 * length

java.lang.Object: 2 * 4 (Object header)

other objects: sizeofSuperClass + 8 * nrOfLongAndDoubleFields + 4 * nrOfIntFloatAndObjectFields + 2 * nrOfShortAndCharFields + 1 * nrOfByteAndBooleanFields -> align result up to a multiple of 8


64 bit

Arrays of boolean, byte, char, short, int: 2 * 8 (Object header) + 4 (length-field) + sizeof(primitiveType) * length -> align result up to a multiple of 8

Arrays of objects: 2 * 8 (Object header) + 4 (length-field) + 4 (dead space due to alignment restrictions) + 8 * length

Arrays of longs and doubles: 2 * 8 (Object header) + 4 (length-field) + 4 (dead space due to alignment restrictions) + 8 * length

java.lang.Object: 2 * 8 (Object header)

other objects: sizeofSuperClass + 8 * nrOfLongDoubleAndObjectFields + 4 + nrOfntAndFloatFields + 2 * nrOfShortAndCharFields + 1 * nrOfByteAndBooleanFields -> align result up to a multiple of 8



Note that an object might have unused space due to alignment at every inheritance level (e.g. imagine a class A with just a byte field and class B has A as it's superclass and declares a byte field itself -> 14 bytes 'wasted on 64 bit system).

In practice 64 bit needs 30 to 50% more memory due to references being twice as large.


[UPDATE]


How much memory does a boolean consume?


Coming back to the question of how much a boolean consumes, yes it does consume at least one byte, but due to alignment rules it may consume much more. IMHO it is more interesting to know that a boolean[] will consume one byte per entry and not one bit,plus some overhead due to alignment and for the size field of the array. There are graph algorithms where large fields of bits are useful, and you need to be aware that, if you use a boolean[] you need almost exactly 8 times more memory than really needed (1 byte versus 1 bit).

Alternatives to boolean[]

To store large sets of booleans more efficiently a standard BitSet can be used. This will pack the bits into a compact representation that only uses one bit per entry (plus some fixed overhead)

For the Eclipse Memory Analyzer we had the need to use large fields of booleans (Millions of entries) and we know in advance how many entries we need.
We therefore implemented the class BitField that is faster than BitSet.

Still we only use this class on single core machines, because the disadvantage of it is that it is not thread save. On multicore machines we use boolean[] and I will explain in a later post how that works, because it's pretty tricky.


Note that these rules tell you only the flat (=shallow) size of an object, which is in practice pretty useless.
I will explain in my next post, how you can better measure how much memory your Java objects consume.

9 comments:

Domingos Neto said...

Hi,

Nice set of rules! Makes it look much simpler than I did :)

Markus Kohler said...

Thanks, got the rules from a JVM hacker here at my company.

Yours is probably more accurate :)
The main problem is, that the rules are constantly changing, but the .hprof heap dump format does not contain any information about those rules.

Bernd Eckenfels said...

You might want to add an sentence what the size of a boolean primitive is and how they (not) align in Arrays. An alternative (BitSet) also exists.

Greetings
Bernd

Markus Kohler said...

Hi Bernd,
Thanks for the hint.
I updated the post.

Greetings,
Markus

Neil Coffey said...

As an extension of this, you might also be interested in a couple of things I've written about memory usage of Java objects:

- if memory usage is crucial to you then (as of Java 5) with slight trickery you can actually query the JVM for the memory size of an object via the Java Instrumentation framework
- it's worth having in mind the memory usage of Strings and possibly other common objects which might have fields you don't naturally think about in the calculation.

Markus Kohler said...

Thanks Neil for the
very interesting references.
That reminds me that I wanted to write again how memory usage in Java (and other languages with a Garbage Collector) can be measured more effectively ...


Regards,
Markus

pbsl said...

you have a nice site.thanks for sharing this site. various kinds of ebooks are available here

http://feboook.blogspot.com

Markus G. said...

Hi Markus,

may I ask you where you get the information that the java.lang.object get the size of two words on the heap (i.e., 32 bit/4 byte word on 32 bit OS and 64bit\8 byte word on a 64 bit OS)?

I can confirm that by checking my heap, but why is this the case? Is this because of the "generality" of this object (root of the class hierarchy)?

Please let me know.

Greetings
Markus G.

Aubin Mahé said...

The reference are not always twice in 64 bits JVM : https://wikis.oracle.com/display/HotSpotInternals/CompressedOops