JVM压缩的Oops背后的技巧

2022-09-01 18:40:32

所以我明白压缩的oops现在在HotSpot VM中默认启用。从Java SE 6u23开始,它通过VM选项对此表示支持。我知道它允许高效的CPU缓存利用率,因为CPU缓存可以容纳比必须处理64位大小的引用更多的引用。但我不明白的是,仅使用32位JVM如何寻址多达2个64个地址。-XX:+UseCompressedOops

为了简化问题,我们如何仅使用2位即可解决多达2个4内存地址?这种地址方案的可能编码/解码是什么?


答案 1

有关压缩 oops 的详细说明,请参阅 John Rose @ Oracle 的“Hotspot JVM 中的 Compressed oops”一文。

TL;DR 版本是:

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

请注意,这仅适用于 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 位字地址。


答案 2

它不适用于 32 位 JVM。这是为了减轻 64 位 JVM 中出现的额外开销。我认为Oracle的页面很好地解释了这一点:

压缩的哎呀

压缩的 oops 表示托管指针(在 JVM 软件中的许多但不是全部位置)为 64 位 Java 堆基址的 32 位对象偏移量。由于它们是对象偏移量而不是字节偏移量,因此它们可用于寻址多达 40 亿个对象(不是字节),或者堆大小高达约 32 GB。要使用它们,必须将它们缩放 8 倍并添加到 Java 堆基址以查找它们引用的对象。