Memory usage of Java objects: general guide
On this page, we take a general look at how to calculate the memory usage of a Java object,
or at least an estimate of its usage. (Note that using the Classmexer agent
from this site— or VM insturmentation generally—
you can query the size of a Java object from within
We'll generally be talking about the
memory taken up on the heap by a given object under "normal circumstances".
A couple of minor complications that we'll gloss over are that:
- in some cases, a JVM may not put an object on the heap at all: for example,
a small thread-local object could in principle be held entirely on the stack or in registers and
not "exist" strictly speaking as a Java heap object;
- the overall memory impact of an object can depend on its current state: for
example, whether its synchronization lock is contended, or whether
it is being garbage collected (such extra "system" data is not necessarily
allocated on the Java heap, however).
On this page, we look at the memory usage of a Java object generally. On the next pages,
we'll look specifically at the memory usage of Strings
and related objects.
General formula for calculating memory usage
In general, the heap memory used by a Java object in Hotspot consists of:
- an object header, consisting of a few bytes of "housekeeping" information;
- memory for primitive fields, according to their size (see below);
- memory for reference fields (4 bytes each);
- padding: potentially a few "wasted" unused bytes after the object data, to make
every object start at an address that is a convenient multiple of bytes and reduce the number of
bits required to represent a pointer to an object.
Sizes of primitive types
In case you're not familiar with the byte size of the different Java primitive data types,
here is the complete list:
|Java type||Bytes required|
You may have expected a boolean to take up a single bit, or an eighth of a byte,
especially if an object had 8 boolean fields. In practice, Hotspot (and, I believe,
VMs generally) allocate a whole byte to each boolean*.
* The reason is simply ease and efficiency of
implementation: generally, we want to assign a "byte offset" to each field of a class and
use a simple instruction to read/write an individual byte.
It would be awkward if we had to cope with sub-byte offsets for certain fields, and
it would require extra logic to read/write individual bits at a given position rather
than just the whole byte each time the boolean was accessed.
Object overhead for "housekeeping" information
Instances of an object on the Java heap don't just take up memory for their actual fields.
Inevitably, they also require some "housekeeping" information, such as recording an object's
class, ID and status flags such as whether the object is currently reachable, currently
- a normal object requires 8 bytes of "housekeeping" space;
- arrays require 12 bytes (the same as a normal object, plus 4 bytes for the array length).
Other JVMs probably have a similar object overhead.
Object size granularity
In Hotspot, every object occupies a number of bytes that is a multiple of 8. If the
number of bytes required by an object for its header and fields is not a multiple 8, then you
round up to the next multiple of 8.
This means, for example, that:
- a bare Object takes up 8 bytes;
- an instance of a class with a single boolean field takes up 16 bytes: 8 bytes of header,
1 byte for the boolean and 7 bytes of "padding" to make the size up to a multiple of 8;
- an instance with eight boolean fields will also take up 16 bytes: 8 for the header,
8 for the booleans; since this is already a multiple of 8, no padding is needed;
- an object with a two long fields, three int fields and a boolean will take
- 8 bytes for the header;
- 16 bytes for the 2 longs (8 each);
- 12 bytes for the 3 ints (4 each);
- 1 byte for the boolean;
- a further 3 bytes of padding, to round the total up from 37 to 40, a multiple of 8.
Memory used by Java arrays
On the next page, we look in more detail at Java array memory usage.