JVM中的指针压缩

1. 什么是JVM的指针压缩?

1.1 前期准备

用的是JDK8





验证代码,使用org.openjdk.jol工具打印的对象布局信息





1.2 开启指针压缩

HotSpot JDK8 默认开启指针压缩(一个User实例占用16bytes

对象头 (Object Header)前8byte是mark word;中间4byte是Class Pointer; 后4byte是属性name





1.3 关闭指针压缩

添加JVM参数“-XX:-UseCompressedOops -XX:-UseCompressedClassPointers ”, 关闭指针压缩(一个User实例占用24bytes

对象头 (Object Header)前8byte是mark word;中间8byte是Class Pointer; 后8byte是属性name





1.4 总结

对于同个一个User实例,在开启指针压缩后减少8bytes(24-16),这就是JVM中指的指针压缩,可以较少JVM上的堆空间占用。



2. 为什么需要JVM的指针压缩?

2.1 指针压缩背景

32位JVM的寻址空间只有2^32(4G),也就是说你的进程最大只能使用4G堆空间。并且由于还存在其他的一些限制,比如说swap空间、内核空间占用、内存碎片等等,实际上jvm可利用的空间要远小于4G,在很多场景下4G空间明显不够用,这就导致64位JVM的发展。

64位JVM,寻址空间最大是2^64,几乎就是无限大了。

2.2 指针压缩原因

因为64位JVM的每一个native指针都占用8个字节,而在32位JVM中只有4字节,加载这些额外的字节会影响内存的占用,且当内存增大了之后,GC停顿时间自然而然的也会跟着变大,因为内存中有更多的垃圾需要来回收了。

64位JVM,提供了更大的寻址空间,也引发内存占用更大,GC停顿时间变大的问题,指针压缩技术就应运而生。



3. 怎么实现JVM的指针压缩?

3.1 原理

官方提到,在 64bits 操作系统上实现 32bits 操作系统一样的指针管理方式,内存可以实现从 4g 到 32g 的提升。

指针压缩有两个过程,分别是编码和解码。编码时候将内存地址右移三位,解码时将内存地址左移三位,解码是在操作内存前,把原来地址左移三位,得到真实的内存地址。编码是指获得到内存地址后,右移三位,得到压缩后的内存地址。

至于为什么要对内存地址进行左右位移操作,是因为内存进行 8bytes 边界对齐后,内存地址的后三位都是 0,根据这个规则,就可以在存储的时候舍弃后面的三位,读取的时候再加上这三位。







3.2 为什么当Xmx大于32G时候,开启指针压缩的参数会失效?

实例如下,设置Xmx=33G, 默认开启指针压缩失效







因为JVM的指针压缩原理采用了8bytes边界对齐和3bit移位算法,所以最大的寻找空间是32G左右。如果指定的空间超过32G,JVM只能退回到8bytes的地址,才能提供超过32G的寻址空间。因此,建议在64位系统下,JAVA的堆内存设置最好不要超过32G,以避免指针压缩失效,触发GC的频次变高,以及造成空间浪费的情况出现。

在实际使用中,也需要注意一些细节问题。例如,需要根据实际业务负载情况和硬件性能来进行合理的内存设置,以达到最优化的效果。





4. 参考资料链接

深入理解Java虚拟机:JVM高级特性与最佳实践(第3版)周志明

32位和64位CPU与内存之间的关系 - 掘金

32位JVM和64位JVM该如何选择? - 知乎

JVM-压缩指针是如何压缩 - 掘金

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值