This leaves the JVM with pointers that can reference 32 GB of memory while using only 32
bits in the heap. However it also means that the JVM cannot access any object at an address
that isn't divisible by 8, since any address from a compressed oop ends with three zeros. The
first possible oop is 0x1, which when shifted becomes 0x8. The next oop is 0x2, which when
shifted becomes 0x10 (16). Objects must therefore be located on an 8-byte boundary.
It turns out that objects are already aligned on an 8-byte boundary in the JVM (in both the
32- and 64-bit versions); this is the optimal alignment for most processors. So nothing is lost
by using compressed oops. If the first object in the JVM is stored at location 0 and occupies
57 bytes, then the next object will be stored at location 64—wasting 7 bytes that cannot be
allocated. That memory trade-off is worthwhile (and will occur whether compressed oops are
used or not), because the object can be accessed faster given that 8-byte alignment.
But that is the reason that the JVM doesn't try to emulate a 36-bit reference that could access
64 GB of memory. In that case, objects would have to be aligned on a 16-byte boundary, and
the savings from storing the compressed pointer in the heap would be outweighed by the
amount of memory that would be wasted in between the memory-aligned objects.
This has two implications. First, for heaps that are between 4 GB and 32 GB, use com-
pressed oops. Compressed oops are enabled using the -XX:+UseCompressedOops flag; in
Java 7 and later versions, they are enabled by default whenever the maximum heap size is
on a 64-bit JVM with a 32 GB heap is 4 bytes—which is the default case since compressed
oops are enabled by default.)
Second, a program that uses a 31 GB heap and compressed oops will usually be faster than a
program that uses a 33 GB heap. Although the 33 GB heap is larger, the extra space used by
the pointers in that heap means that the larger heap will perform more frequent GC cycles
and have worse performance.
Hence, it is better to use heaps that are less than 32 GB, or heaps that are at least a few GB
larger than 32 GB. Once extra memory is added to the heap to make up for the space used by
the uncompressed references, the number of GC cycles will be reduced. There is no hard rule
there for how much memory is needed before the GC impact of the uncompressed oops is
ameliorated—but given that 20% of an average heap might be used for object references,
planning on at least 38 GB is a good start.