所以我理解现在默认情况下在HotSpot VM中启用了压缩的oops。从Java SE 6u23开始,它通过VM选项-XX:+UseCompressedOops
支持此功能。我知道它允许有效的CPU缓存利用率,因为CPU缓存可以容纳大量的引用,而不是它们必须处理64位大小的引用。但我不明白的是,如果只使用32位JVM,最多可以处理2个 64 地址。
为了简化问题,我们如何仅使用2位来处理最多2个 4 存储器地址?什么可能是这种地址方案的编码/解码?
答案 0 :(得分:28)
有关压缩oops的详细说明,请参阅John Rose @ Oracle的"Compressed oops in the Hotspot JVM"文章。
TL; DR版本是:
请注意, only 适用于64位JVM。我们仍然需要能够处理包含(最多)32 GB堆 1 的内存,这意味着64位硬件地址(在现代CPU /计算机体系结构上)。
另请注意,执行此操作会受到轻微惩罚;即在常规参考和压缩参考之间转换所需的移位指令。然而,另一方面是消耗的实际内存较少 3 ,因此内存缓存通常更有效。
1 - 这是因为现代计算机体系结构针对字对齐内存访问进行了优化。
2 - 假设您没有使用-XX:ObjectAlignmentInBytes
将对齐方式从其默认(和最小)值8字节增加。
3 - 实际上,内存节省是特定于应用程序的。它取决于平均对象对齐浪费,参考与非参考字段的比率等。如果考虑调整对象对齐,它会变得更复杂。
为了简化问题,我们如何仅使用2位来处理多达2个 4 内存地址?什么可能是这种地址方案的编码/解码?
您无法处理2个 4 字节地址。但是可以使用2位字地址来寻址2个 2 字地址(假设32位字)。如果您可以假设所有字节地址都是字对齐的,那么您可以将4位字节地址压缩为2位字地址,方法是将其移位2位。
答案 1 :(得分:9)
它不适用于32位JVM。这是为了减轻64位JVM中发生的额外开销。我认为Oracle的页面解释得很好:
压缩哎呀
压缩的oops代表托管 指针(在JVM软件中很多但不是所有地方)都是32位的 来自64位Java堆基址的对象偏移量。因为他们是 对象偏移而不是字节偏移,它们可用于寻址 最多40亿个对象(不是字节),或堆大小最多约 32千兆字节。要使用它们,它们必须按比例缩放8倍 添加到Java堆基址以查找它们所对应的对象 参考。
答案 2 :(得分:0)
从文章: 并非所有指针都被压缩,压缩的指针是32位值,必须按8倍缩放,并添加到64位基址以查找它们所引用的对象。
现在请注意,您无法使用这些32位指针寻址2 ^ 64位内存,但您可以使用它们访问大量Objects
。如果您在内存位置x
处有一个对象,那么您无法在x+1
处拥有另一个对象。这就是您不需要访问每个内存位置的原因。
答案 3 :(得分:0)
https://blog.codecentric.de/en/2014/02/35gb-heap-less-32gb-java-jvm-memory-oddities/
我认为本文对此做了很好的解释。带走:
因为JVM内存布局使用8字节寻址方案,这意味着对象可以位于地址0、8、16、24…,但不能位于2、7或8的任何其他非整数倍,压缩oop只能寻址虚拟机。位置0、1、2、3而不是真实的0、8、16、24。要从压缩地址转换为真实地址,JVM只需将其左移3次即可。容易。
4G * 8 = 32