In this article, you will learn how “Compressed Oops” is used on a 64-bit system to represent references to Java objects with only 32 bits instead of 64, and how this significantly reduces the memory requirements of a Java application.
What is a 64-Bit System?
A 64-bit system is characterized by the fact that pointers to addresses in memory are 64-bit long. This means we can address 264 bytes = 16 exabytes = 18,446,744,073,709,551,616 bytes.
Nowadays, there are practically no programs that require this much memory. In ten years, we might smile at this statement ;-)
Here is the graphical representation of such a 64-bit pointer:
Now you could consider dividing these 64 bits in half and storing not just one but two pointers with the same amount of memory:
However, with 32 bits, we can address only 232 bytes = 4 GB. That is not enough for many applications.
The JDK developers have, therefore, devised a clever trick (“Compressed Oops”) to address not just 4 GB but 32 GB using only 32 bits. And that, in turn, is sufficient for most applications today.
How does Compressed Oops Work?
Compressed Oops (OOP stands for “ordinary object pointer”) allows an address space of 235 = 32 gigabytes to be addressed using 32-bit pointers.
How is that possible? To address 32 gigabytes, we would actually need 35 bits. But we cannot store 35 bits in a 32-bit int; for that, we would need the next largest data structure, a 64-bit long:
So we would have wasted 29 bits. Then we could have stuck with 64-bit pointers.
It's time to use a trick!
First of all, we position all Java objects at memory addresses that are divisible by eight. Eight is equal to 23, which means that the last 3 bits of a pointer are always 0. Therefore, only the upper 32 bits contain relevant information:
Since we know that the last three bits are always 0, we do not need to store them every time. Therefore, the 35-bit memory address can be shifted right by three bits without any loss of information and thus stored in a 32-bit field:
To access the uncompressed memory address again later, the 32 bits simply have to be shifted left by three bits.
Compressed Oops are Enabled by Default
On a 64-bit system with a maximum of 32 GB heap, Compressed OOPs are enabled by default. If the heap size is more than 32 GB, we cannot use Compressed Oops (because they can only address 32 GB).
You can turn off Compressed Oops with the following VM option:
-XX:-UseCompressedOops
Why should one do that?
Compressing and decompressing pointers costs time. Not much, as the required shift operation can usually be performed in a single CPU cycle. However, those who want to squeeze the last bit of performance out of their application and are willing to accept the increased memory requirement (all pointers occupy 64 instead of 32 bits) can consider this option.
Conclusion
Compressed Oops allows you to encode memory addresses with only 32 bits instead of 64 on a 64-bit system with a heap size of up to 32 GB. Since there is at least one pointer to every active Java object in an application, Compressed Oops significantly reduces the memory requirements of an application.
Want to keep up to date with all the new Java features? Then click here to sign up for the HappyCoders newsletter.