躲在JVM压缩的Oops后面

时间:2014-08-04 14:02:38

标签: java memory-management jvm

所以我理解现在默认情况下在HotSpot VM中启用了压缩的oops。从Java SE 6u23开始,它通过VM选项-XX:+UseCompressedOops支持此功能。我知道它允许有效的CPU缓存利用率,因为CPU缓存可以容纳大量的引用,而不是它们必须处理64位大小的引用。但我不明白的是,如果只使用32位JVM,最多可以处理2个 64 地址。

为了简化问题,我们如何仅使用2位来处理最多2个 4 存储器地址?什么可能是这种地址方案的编码/解码?

4 个答案:

答案 0 :(得分:28)

有关压缩oops的详细说明,请参阅John Rose @ Oracle的"Compressed oops in the Hotspot JVM"文章。

TL; DR版本是:

  • 在现代计算机体系结构上,内存地址是字节地址,
  • Java对象引用是指向单词 1
  • 的开头的地址
  • 在64位机器上,字对齐意味着对象引用/地址的底部3位为零 2
  • 所以,通过将地址向右移3位,我们可以"压缩"高达35位的64位地址到32位字,
  • 并且,可以通过将3位向左移位来完成解压缩,这将3个零位置回来,
  • 35位寻址允许我们使用在64位计算机上适合32位(半)字的压缩oops来表示最多32 GB堆内存的对象指针。

请注意, 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堆基址以查找它们所对应的对象   参考。

source

答案 2 :(得分:0)

CompressedOops

从文章: 并非所有指针都被压缩,压缩的指针是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