How to calculate the memory usage of a Java array
Following on from our discussion of the memory usage of Java objects,
on this page, we consider the special case of arrays. Recall that:
- in Java, an array is a special type of object;
- a multi-dimensional array is simple an array of arrays;
- for example, in a two-dimensional array,
every row is a separate array object.
(To query the memory usage of an array from within a Java program,
you can use the memory utility class of the
Classmexer agent available from this site.)
Memory usage of a single-dimension array
A single-dimension array is a single object. As expected, the array has the usual object
header. However, this object head is 12 bytes to accommodate a
four-byte array length. Then comes the actual array data which, as you
might expect, consists of the number of elements multiplied by the number of bytes required
for one element, depending on its type. The memory usage for one element is 4 bytes for an object reference;
for a list of the memory usage of primitive types, see the page on
Java data types. If the total memory usage of the
array is not a multiple of 8 bytes, then the size is rounded up to the next mutlitple of 8 (just as
for any other object).
Note that a boolean array requires one byte per element, even though each
element actually only stores a single bit of useful information. (If you need to store a series
of bits more compactly, see the BitSet class.)
Memory usage of a two-dimensional array
In a language such as C, a two-dimensional array (or indeed any multidimensional array)
is essentially a one-dimensional array
with judicious pointer manipulation. This is not the case in Java, where a multidimensional
array is actually a set of nested arrays. This means that every row
of a two-dimensional array has the overhead of an object, since it actually
is a separate object!
For example, let's consider a 10x10 int array. Firstly, the "outer" array has its
12-byte object header followed by space for the 10 elements. Those elements are object references
to the 10 arrays making up the rows. That comes to 12+4*10=52 bytes, which must then be rounded
up to the next multiple of 8, giving 56. Then, each of the 10 rows has its own 12-byte object
header, 4*10=40 bytes for the actual row of ints, and again, 4 bytes of padding to
bring the total for that row to a multiple of 8. So in total, that gives 11*56=616 bytes.
That's a bit bigger than if you'd just counted on 10*10*4=400 bytes for the hundred "raw" ints
For arrays of more than 2 dimensions, the above logic repeats: each row of the "outer" array
is now an array of references to a further array, which contains the actual primitive data
(or references if it is an object array).