On this page, we take a general look at how to calculate the memory usage of a Java object, or at least anestimate 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 your program.)
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 iscontended, 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 thememory usage ofStrings 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 |
---|---|
boolean | 1 |
byte | |
char | 2 |
short | |
int | 4 |
float | |
long | 8 |
double |
2B, CS,IPHONE,老爹
You may have expected a boolean to take up a single bit, or an eighth of a byte, especially if an object had 8boolean 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 synchronization-locked etc.
- 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 youround 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 up:
- 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.