JVM在64位系统上的指针压缩

记录下JVM在64位系统上的指针压缩。

寻址能力不同是32位与64位操作系统的不同之处。

32位操作系统最大支持4G内存(2^32),而64位操作系理论上最大支持16384PB(2^64)

指针占用字节的不同:

  • 64位JVM占用8个字节
  • 32位JVM占用4个字节

同样的指针加载,64位JVM会占用更多的内存,也就是所谓的"64位JVM是32位JVM内存消耗的1.5位"

CompressedOops与UseCompressedClassPointers

CompressedOops与UseCompressedClassPointers是用来压缩空间的,用于解决JVM在32位与64位操作系统上内存占用问题。

CompressedOops是指开启普通对象指针的压缩(Ordinary Object Pointer),用于提高堆的使用效率。

UseCompressedClassPointers是指开启类指针压缩。

堆内存在"4G~32G"的范围内,可使用指针压缩技术来提高堆内存的使用效率。


举例

1
2
3
class A { int a; }

`A a = new A()`,

HotSpot的对齐方式为8字节对齐:

对象内存 = 对象头 + 实例数据 + padding,

其中 0 <= padding < 8。

64位系统的JVM默认(未开启指针压缩)情况下,指针a(引用)占用8个字节,对应的对象占用24个字节:

1
24(对象内存, 8字节对齐) = 16(对象头) + 4(int a)+ 4 (padding 补位对齐)

64位系统的JVM默认(开启指针压缩)情况下,指针a(引用)占用4个字节,对应的对象占用16个字节:

1
16(对象内存, 8字节对齐) = 12(对象头) + 4(int a)+ 0 (padding 补位对齐)

CompressedOopsUseCompressedClassPointers必须同时使用(默认开启),否则无法生效。

Java8默认开启了这个配置,在没有配置MetaspaceSize的情况下,会自动申请1G大小的CompressedClassSpaceSize

MetaSpace用来存储klass(JVM中class的运行时数据结构)的。

无论如何配置,CompressedClassSpaceSize总是小于MetaspaceSize(默认为宿主机的最大内存)

开启命令如下,

1
2
3
-XX:+UseCompressedClassPointers
-XX:+UseCompressedOops
-XX:CompressedClassSpaceSize=128m

但一般我们只需要设置好MetaSpace,如下

1
2
-XX:MetaspaceSize=128m
-XX:MaxMetaspaceSize=128m

JVM会默认开启指针压缩,并且自动配置CompressedClassSpaceSize的大小。

非堆内存划分

CodeCache:用于存储经过JIT编译优化后的代码

JIT编译器(即时编译器)生成Hot Spot Code(热点代码),从而提高执行效率。

MetaSpace:用于存储Class在JVM中的数据结构klass,包含类的所有元数据数据(方法、字节码、常量池等)。

CompressedClassSpace:是分配在MetaSpace中,用于指令压缩,只包含类的部分元数据(InstansKlass/ArrayKlass等)。