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
Trick behind JVM's compressed Oops
提问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:ObjectAlignmentInBytes
to 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 堆基地址中以找到它们所引用的对象。
回答by Kayaman
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 Objects
with 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