Autoboxing can come at a substantial memory overhead. For example:
Map<Integer, Integer> square = new HashMap<Integer, Integer>();
for(int i = 256; i < 1024; i++) {
square.put(i, i * i); // Autoboxing of large integers
}
will typically consume substantial amount of memory (about 60kb for 6k of actual data).
Furthermore, boxed integers usually require additional round-trips in the memory, and thus make CPU caches less effective. In above example, the memory accessed is spread out to five different locations that may be in entirely different regions of the memory: 1. the HashMap
object, 2. the map's Entry[] table
object, 3. the Entry
object, 4. the entrys key
object (boxing the primitive key), 5. the entrys value
object (boxing the primitive value).
class Example {
int primitive; // Stored directly in the class `Example`
Integer boxed; // Reference to another memory location
}
Reading boxed
requires two memory accesses, accessing primitive
only one.
When getting data from this map, the seemingly innocent code
int sumOfSquares = 0;
for(int i = 256; i < 1024; i++) {
sumOfSquares += square.get(i);
}
is equivalent to:
int sumOfSquares = 0;
for(int i = 256; i < 1024; i++) {
sumOfSquares += square.get(Integer.valueOf(i)).intValue();
}
Typically, the above code causes the creation and garbage collection of an Integer
object for every Map#get(Integer)
operation. (See Note below for more details.)
To reduce this overhead, several libraries offer optimized collections for primitive types that do not require boxing. In addition to avoiding the boxing overhead, these collection will require about 4x less memory per entry. While Java Hotspot may be able to optimize the autoboxing by working with objects on the stack instead of the heap, it is not possible to optimize the memory overhead and resulting memory indirection.
Java 8 streams also have optimized interfaces for primitive data types, such as IntStream
that do not require boxing.
Note: a typical Java runtime maintains a simple cache of Integer
and other primitive wrapper object that is used by the valueOf
factory methods, and by autoboxing. For Integer
, the default range of this cache is -128 to +127. Some JVMs provide a JVM command-line option for changing the cache size / range.