gpt4 book ai didi

java-8 - java8 -XX :+UseCompressedOops -XX:ObjectAlignmentInBytes=16

转载 作者:行者123 更新时间:2023-12-04 10:48:31 26 4
gpt4 key购买 nike

所以,我正在尝试运行一些简单的代码,jdk-8,通过 jol 输出

    System.out.println(VMSupport.vmDetails());
Integer i = new Integer(23);
System.out.println(ClassLayout.parseInstance(i)
.toPrintable());

第一次尝试是在 64 位 JVM 上禁用压缩 oops 和压缩 klass 来运行它。
-XX:-UseCompressedOops -XX:-UseCompressedClassPointers

几乎预期的输出是:
Running 64-bit HotSpot VM.
Objects are 8 bytes aligned.

java.lang.Integer object internals:
OFFSET SIZE TYPE DESCRIPTION VALUE
0 4 (object header) 01 00 00 00 (00000001 00000000 00000000 00000000) (1)
4 4 (object header) 00 00 00 00 (00000000 00000000 00000000 00000000) (0)
8 4 (object header) 48 33 36 97 (01001000 00110011 00110110 10010111) (-1758055608)
12 4 (object header) 01 00 00 00 (00000001 00000000 00000000 00000000) (1)
16 4 int Integer.value 23
20 4 (loss due to the next object alignment)

Instance size: 24 bytes (reported by Instrumentation API)
Space losses: 0 bytes internal + 4 bytes external = 4 bytes total

这是有道理的:8 字节 klass 字 + 8 字节标记字 + 4 字节用于实际值,4 字节用于填充(对齐 8 字节)= 24 字节。

第二次尝试在 64 位 JVM 上使用启用了压缩 oops 的压缩 klass 运行它。

同样,输出非常容易理解:
Running 64-bit HotSpot VM.
Using compressed oop with 3-bit shift.
Using compressed klass with 3-bit shift.
Objects are 8 bytes aligned.

OFFSET SIZE TYPE DESCRIPTION VALUE
0 4 (object header) 01 00 00 00 (00000001 00000000 00000000 00000000) (1)
4 4 (object header) 00 00 00 00 (00000000 00000000 00000000 00000000) (0)
8 4 (object header) f9 33 01 f8 (11111001 00110011 00000001 11111000) (-134138887)
12 4 int Dummy.i 42
Instance size: 16 bytes (reported by Instrumentation API).

4 字节压缩 oop(klass 字)+ 8 字节标记字 + 4 字节用于值 + 无空间损失 = 16 字节。

对我来说没有意义的是这个用例:
 -XX:+UseCompressedOops -XX:+UseCompressedClassPointers -XX:ObjectAlignmentInBytes=16

输出是这样的:
 Running 64-bit HotSpot VM.
Using compressed oop with 4-bit shift.
Using compressed klass with 0x0000001000000000 base address and 0-bit shift.

我真的期待两者都是“4位移位”。为什么他们不是?

编辑
第二个示例运行:
 XX:+UseCompressedOops -XX:+UseCompressedClassPointers

第三个是:
 -XX:+UseCompressedOops -XX:+UseCompressedClassPointers -XX:ObjectAlignmentInBytes=16

最佳答案

我将尝试扩展 Alexey 提供的答案,因为有些事情可能并不明显。

按照 Alexey 的建议,如果我们在 OpenJDK 的源代码中搜索压缩 klass 位移值的分配位置,我们会在 metaspace.cpp 中找到以下代码:

void Metaspace::set_narrow_klass_base_and_shift(address metaspace_base, address cds_base) {
// some code removed
if ((uint64_t)(higher_address - lower_base) <= UnscaledClassSpaceMax) {
Universe::set_narrow_klass_shift(0);
} else {
assert(!UseSharedSpaces, "Cannot shift with UseSharedSpaces");
Universe::set_narrow_klass_shift(LogKlassAlignmentInBytes);
}

正如我们所见,类移位可以是 0(或基本上不移位)或 3 位,因为 LogKlassAlignmentInBytes 是 globalDefinitions.hpp 中定义的常量:
const int LogKlassAlignmentInBytes = 3;

所以,你的问题的答案:

I was really expecting to both be "4-bit shift". Why they are not?



是 ObjectAlignmentInBytes 对始终为 8 字节的元空间中的压缩类指针对齐没有任何影响。

当然,这个结论并不能回答这个问题:

“为什么将 -XX:ObjectAlignmentInBytes=16 与 -XX:+UseCompressedClassPointers 一起使用时,窄类移位变为零?此外,如果堆为 4GB 或更多,那么在不移位的情况下,JVM 如何使用 32 位引用引用类空间?”

我们已经知道类空间分配在 java 堆的顶部,最大可以达到 3G。考虑到这一点,让我们进行一些测试。 -XX:+UseCompressedOops -XX:+UseCompressedClassPointers 默认是启用的,所以为了简洁我们可以去掉这些。

测试 1:默认值 - 8 字节对齐
$ java -XX:ObjectAlignmentInBytes=8 -XX:+UnlockDiagnosticVMOptions -XX:+PrintCompressedOopsMode -version

heap address: 0x00000006c0000000, size: 4096 MB, zero based Compressed Oops

Narrow klass base: 0x0000000000000000, Narrow klass shift: 3
Compressed class space size: 1073741824 Address: 0x00000007c0000000 Req Addr: 0x00000007c0000000

请注意,堆从虚拟空间中的地址 0x00000006c0000000 开始,大小为 4GB。让我们从堆开始的地方跳 4GB,然后我们就在类空间开始的地方着陆。
0x00000006c0000000 + 0x0000000100000000 = 0x00000007c0000000

类空间大小是 1Gbyte,所以让我们再跳 1Gbyte:
0x00000007c0000000 + 0x0000000040000000 = 0x0000000800000000

我们降落在 32GB 以下。通过 3 位类空间移位,JVM 能够引用整个类空间,尽管它处于限制(有意)。

测试 2:16 字节对齐
java -XX:ObjectAlignmentInBytes=16 -XX:+UnlockDiagnosticVMOptions -XX:+PrintCompressedOopsMode -version

heap address: 0x0000000f00000000, size: 4096 MB, zero based Compressed Oops

Narrow klass base: 0x0000001000000000, Narrow klass shift: 0
Compressed class space size: 1073741824 Address: 0x0000001000000000 Req Addr: 0x0000001000000000

这次我们可以观察到堆地址不同,但让我们尝试相同的步骤:
0x0000000f00000000 + 0x0000000100000000 = 0x0000001000000000

这一次堆空间刚好在 64GBytes 虚拟空间边界之下结束,并且类空间分配在 64Gbyte 边界之上。由于类空间只能使用 3 位移位,那么 JVM 如何引用位于 64Gbyte 以上的类空间呢?关键是:
Narrow klass base: 0x0000001000000000

JVM 仍然为类空间使用 32 位压缩指针,但是在对这些进行编码和解码时,它总是将 0x0000001000000000 基址添加到压缩引用中,而不是使用移位。请注意,只要引用的内存块低于 4GB(32 位引用的限制),这种方法就可以工作。考虑到类空间最多可以有 3GB,我们可以轻松地在限制范围内。

3:16 字节对齐,引脚堆基数为 8g
$ java -XX:ObjectAlignmentInBytes=16 -XX:HeapBaseMinAddress=8g -XX:+UnlockDiagnosticVMOptions -XX:+PrintCompressedOopsMode -version

heap address: 0x0000000200000000, size: 4096 MB, zero based Compressed Oops

Narrow klass base: 0x0000000000000000, Narrow klass shift: 3
Compressed class space size: 1073741824 Address: 0x0000000300000000 Req Addr: 0x0000000300000000

在这个测试中,我们仍然保持 -XX:ObjectAlignmentInBytes=16,但还要求 JVM 使用 -XX:HeapBaseMinAddress=8g JVM 参数在虚拟地址空间中的第 8 GByte 处分配堆。类空间将从虚拟地址空间中的第 12 GByte 开始,并且 3 位移位足以引用它。

希望这些测试及其结果回答了这个问题:

"Why when using -XX:ObjectAlignmentInBytes=16 with -XX:+UseCompressedClassPointers the narrow klass shift becomes zero? Also, without shifting how can the JVM reference the class space with 32-bit references, if the heap is 4GBytes or more?"

关于java-8 - java8 -XX :+UseCompressedOops -XX:ObjectAlignmentInBytes=16,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35411754/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com