java JVM 压缩的 Oops 背后的技巧

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/25120546/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-11-02 07:23:24  来源:igfitidea点击:

Trick behind JVM's compressed Oops

javamemory-managementjvm

提问by Geek

So I understand the compressed oops is enabled by default in HotSpot VM now. It has support for this from Java SE 6u23 onwards through the VM option -XX:+UseCompressedOops. I understand that it allows for efficient CPU cache utilization as the CPU caches can hold a larger number of references than if they had to deal with 64 bit sized references. But what I do not understand is how using only 32 bits JVM can address up to 264addresses.

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

To simplify the problem how can we address up to 24memory address's using just 2 bits? What can be a possible encoding/decoding of such an address scheme?

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

回答by Stephen C

For a detailed explanation of compressed oops, see the "Compressed oops in the Hotspot JVM"article by John Rose @ Oracle.

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

The TL;DR version is:

TL;DR 版本是:

  • on modern computer architectures, memory addresses are byte addresses,
  • Java object references are addresses that point to the start of a word1,
  • on a 64-bit machine, word alignment means that that the bottom 3 bits of an object reference / address are zero2
  • so, by shifting an address 3 bits to the right, we can "compress" up to a 35 bits of a 64 bit address into a 32-bit word,
  • and, decompression can be done by shifting 3 bits to the left, which puts those 3 zero bits back,
  • 35 bits of addressing allows us to represent object pointers for up to 32 GB of heap memory using compressed oops that fit in 32-bit (half-)words on a 64-bit machine.
  • 在现代计算机体系结构中,内存地址是字节地址,
  • Java 对象引用是指向单词1开头的地址,
  • 在 64 位机器上,字对齐意味着对象引用/地址的低 3 位为零2
  • 因此,通过将地址右移 3 位,我们可以将 64 位地址的最多 35 位“压缩”为 32 位字,
  • 并且,可以通过向左移动 3 位来完成解压缩,这将把这 3 个零位放回原处,
  • 35 位寻址允许我们使用适合 64 位机器上的 32 位(半)字的压缩 oops 来表示最多 32 GB 堆内存的对象指针。


Note that this onlyworks on a 64-bit JVM. We still need to be able to address the memory containing that (up to) 32 GB heap1, and that means 64-bit hardware addresses (on modern CPUs / computer architectures).

请注意,这适用于 64 位 JVM。我们仍然需要能够寻址包含(最多)32 GB 堆1的内存,这意味着 64 位硬件地址(在现代 CPU/计算机架构上)。

Note also that there is a small penalty in doing this; i.e. the shift instructions required to translate between regular and compressed references. However, the flip side is that less actual memory is consumed3, and memory caches are typically more effective as a consequence.

还要注意,这样做会有一个小惩罚;即在常规引用和压缩引用之间转换所需的移位指令。然而,另一方面是消耗的实际内存较少3,因此内存缓存通常更有效。

1 - This is because modern computer architectures are optimized for word-aligned memory access.

1 - 这是因为现代计算机体系结构针对字对齐内存访问进行了优化。

2 - This assumes that you haven't used -XX:ObjectAlignmentInBytesto increase the alignment from its default (and minimum) value of 8 bytes.

2 - 这假设您没有使用-XX:ObjectAlignmentInBytes过从其默认(和最小)值 8 字节增加对齐。

3 - In fact, the memory saving is application specific. It depends on the average object alignment wastage, ratios of reference to non-reference fields and so on. It gets more complicated if you consider tuning the object alignment.

3 - 事实上,内存节省是特定于应用程序的。这取决于平均对象对齐损耗、参考与非参考字段的比率等。如果您考虑调整对象对齐,它会变得更加复杂。



To simplify the problem how can we address up to 24memory addresses using just 2 bits? What can be a possible encoding/decoding of such an address scheme?

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

You can't address 24byte addresses. But you canaddress 22word addresses (assuming 32-bit words) using 2-bit word addresses. If you can assume that all byte addresses are word-aligned, then you can compress a 4-bit byte address as 2-bit word address by shifting it by 2-bit positions.

您无法寻址 2 个4字节的地址。但是您可以使用 2 位字地址寻址 2 个2字地址(假设为 32 位字)。如果您可以假设所有字节地址都是字对齐的,那么您可以通过将 4 位字节地址移位 2 位位置来将其压缩为 2 位字地址。

回答by Enno Shioji

It's not meant for 32-bit JVMs. It's to alleviate the additional overhead that occur in 64-bit JVMs. I think Oracle's page explains it well:

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

Compressed Oops

Compressed oops represent managed pointers (in many but not all places in the JVM software) as 32-bit object offsets from the 64-bit Java heap base address. Because they're object offsets rather than byte offsets, they can be used to address up to four billion objects (not bytes), or a heap size of up to about 32 gigabytes. To use them, they must be scaled by a factor of 8 and added to the Java heap base address to find the object to which they refer.

压缩的哎呀

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

source

来源

回答by Kayaman

CompressedOops.

压缩的哎呀

From the article: Not all of the pointers are compressed, and the compressed ones are 32-bit values which must be scaled by a factor of 8 and added to a 64-bit base address to find the object they refer to.

来自文章:并非所有指针都被压缩,压缩的指针是 32 位值,必须按因子 8 缩放并添加到 64 位基地址以找到它们引用的对象。

Now note that you can't address 2^64 bits of memory with these 32bit pointers, but you can access plenty of Objectswith them. If you have an object at memory location x, there's no way that you can have another one at x+1. That's why you don't need to access every single memory location.

现在请注意,您无法使用这些 32 位指针寻址 2^64 位内存,但您可以Objects使用它们访问大量内存。如果您在内存位置有一个对象x,则您无法在x+1. 这就是为什么您不需要访问每个内存位置的原因。

回答by Jiacai Liu

https://blog.codecentric.de/en/2014/02/35gb-heap-less-32gb-java-jvm-memory-oddities/

https://blog.codecentric.de/en/2014/02/35gb-heap-less-32gb-java-jvm-memory-oddities/

I think this article explain this well. Taken away:

我认为这篇文章很好地解释了这一点。带走了:

Because the JVM memory layout uses a 8byte addressing scheme, which means that objects can be at address 0, 8, 16, 24… but not at 2, 7 or any other non multiple of 8, compressed oops just address the virtual positions 0, 1, 2, 3 instead of the real ones 0, 8, 16, 24. To get from the compressed address to the real one, the JVM needs just to left shift it 3 times. Easy.

因为 JVM 内存布局使用 8 字节寻址方案,这意味着对象可以位于地址 0、8、16、24……但不能位于 2、7 或任何其他非 8 的倍数,压缩的 oops 只寻址虚拟位置 0, 1, 2, 3 而不是真正的 0, 8, 16, 24。为了从压缩地址到真正的地址,JVM 只需要将它左移 3 次。简单。

4G * 8 = 32

4G * 8 = 32