当前位置:网站首页>JVM 的指针压缩
JVM 的指针压缩
2022-06-27 00:47:00 【唐伯虎点蚊香dw】
在介绍完关于内存对齐的相关内容之后,我们来介绍下前边经常提到的压缩指针。可以通过JVM参数XX:+UseCompressedOops开启,当然默认是开启的。
在本小节内容开启之前,我们先来讨论一个问题,那就是为什么要使用压缩指针??
假设我们现在正在准备将32位系统切换到64位系统,起初我们可能会期望系统性能会立马得到提升,但现实情况可能并不是这样的。
在JVM中导致性能下降的最主要原因就是64位系统中的对象引用。在前边我们也提到过,64位系统中对象的引用以及类型指针占用64 bit也就是8个字节。
这就导致了在64位系统中的对象引用占用的内存空间是32位系统中的两倍大小,因此间接的导致了在64位系统中更多的内存消耗以及更频繁的GC发生,GC占用的CPU时间越多,那么我们的应用程序占用CPU的时间就越少。
另外一个就是对象的引用变大了,那么CPU可缓存的对象相对就少了,增加了对内存的访问。综合以上几点从而导致了系统性能的下降。
从另一方面来说,在64位系统中内存的寻址空间为2^48 = 256T,在现实情况中我们真的需要这么大的寻址空间吗??好像也没必要吧~~
于是我们就有了新的想法:那么我们是否应该切换回32位系统呢?
如果我们切换回32位系统,我们怎么解决在32位系统中拥有超过4G的内存寻址空间呢?因为现在4G的内存大小对于现在的应用来说明显是不够的。
我想以上的这些问题,也是当初JVM的开发者需要面对和解决的,当然他们也交出了非常完美的答卷,那就是使用压缩指针可以在64位系统中利用32位的对象引用获得超过4G的内存寻址空间。
7.1 压缩指针是如何做到的呢?
还记得之前我们在介绍对齐填充和内存对齐小节中提到的,在Java虚拟机堆中对象的起始地址必须对齐至8的倍数吗?
由于堆中对象的起始地址均是对齐至8的倍数,所以对象引用在开启压缩指针情况下的32位二进制的后三位始终是0(因为它们始终可以被8整除)。
既然JVM已经知道了这些对象的内存地址后三位始终是0,那么这些无意义的0就没必要在堆中继续存储。相反,我们可以利用存储0的这3位bit存储一些有意义的信息,这样我们就多出3位bit的寻址空间。
这样在存储的时候,JVM还是按照32位来存储,只不过后三位原本用来存储0的bit现在被我们用来存放有意义的地址空间信息。
当寻址的时候,JVM将这32位的对象引用左移3位(后三位补0)。这就导致了在开启压缩指针的情况下,我们原本32位的内存寻址空间一下变成了35位。可寻址的内存空间变为2^32 * 2^3 = 32G。

压缩指针.png
这样一来,JVM虽然额外的执行了一些位运算但是极大的提高了寻址空间,并且将对象引用占用内存大小降低了一半,节省了大量空间。况且这些位运算对于CPU来说是非常容易且轻量的操作
通过压缩指针的原理我挖掘到了内存对齐的另一个重要原因就是通过内存对齐至8的倍数,我们可以在64位系统中使用压缩指针通过32位的对象引用将寻址空间提升至32G.
从Java7开始,当maximum heap size小于32G的时候,压缩指针是默认开启的。但是当maximum heap size大于32G的时候,压缩指针就会关闭。
那么我们如何在压缩指针开启的情况下进一步扩大寻址空间呢???
7.2 如何进一步扩大寻址空间
前边提到我们在Java虚拟机堆中对象起始地址均需要对其至8的倍数,不过这个数值我们可以通过JVM参数-XX:ObjectAlignmentInBytes 来改变(默认值为8)。当然这个数值的必须是2的次幂,数值范围需要在8 - 256之间。
正是因为对象地址对齐至8的倍数,才会多出3位bit让我们存储额外的地址信息,进而将4G的寻址空间提升至32G。
同样的道理,如果我们将ObjectAlignmentInBytes的数值设置为16呢?
对象地址均对齐至16的倍数,那么就会多出4位bit让我们存储额外的地址信息。寻址空间变为2^32 * 2^4 = 64G。
通过以上规律,我们就能知道,在64位系统中开启压缩指针的情况,寻址范围的计算公式:4G * ObjectAlignmentInBytes = 寻址范围。
但是笔者并不建议大家贸然这样做,因为增大了ObjectAlignmentInBytes虽然能扩大寻址范围,但是这同时也可能增加了对象之间的字节填充,导致压缩指针没有达到原本节省空间的效果。
边栏推荐
- 解决STC8G1K08程序不能运行的问题和端口配置
- Find the minimum value in the rotation sort array ii[classical Abstract dichotomy + how to break the game left, middle and right are equal]
- 你的case真的pass了吗?
- memcached基础5
- Operating instructions and Q & A of cec-i China learning machine
- ML:机器学习工程化之团队十大角色背景、职责、产出物划分之详细攻略
- Amazon elasticache quickly builds a cache service cluster, which is fast
- get_sequencer的用法总结
- Flink 实战问题(七):No Watermark(Watermarks are only available EventTime is used)
- Central Limit Theorem
猜你喜欢

Amazon ElastiCache 飞速搭建缓存服务集群,这才叫快
![Find the minimum value in the rotation sort array ii[classical Abstract dichotomy + how to break the game left, middle and right are equal]](/img/75/05d5765588dfde971167fbc72e2aa8.png)
Find the minimum value in the rotation sort array ii[classical Abstract dichotomy + how to break the game left, middle and right are equal]

Bootstrapblazor + FreeSQL actual combat chart usage (2)

3-wire SPI screen driving mode

ESP32-SOLO开发教程,解决CONFIG_FREERTOS_UNICORE问题

CH423要如何使用,便宜的国产IO扩展芯片

Operating instructions and Q & A of cec-i China learning machine

Two days of beautiful butterfly animation

How to control the quality of HD slip ring in the production process

The world is very big. Some people tattoo QR codes on their necks
随机推荐
getReader() has already been called for this request
ESP32实验-自建web服务器配网02
微博评论高性能高可用架构
Custom class loader encrypts and decrypts classes
UVM中uvm_config_db非直线的设置与获取
Topolvm: kubernetes local persistence scheme based on LVM, capacity aware, dynamically create PV, and easily use local disk
Gaussian and Summary Stats
Great vernacular with high concurrency (I)
解决u8glib只显示一行文字或者不显示的问题
对象的访问机制及其他
These 10 copywriting artifacts help you speed up the code. Are you still worried that you can't write a copywriting for US media?
Keepalived 实现 Redis AutoFailover (RedisHA)17
memcached基础4
UVM中config_db机制的使用方法
Interface test framework practice (I) | requests and interface request construction
Timing mechanism of LwIP
Keepalived 实现 Redis AutoFailover (RedisHA)12
USB协议中HID设备描述符以及键盘按键值对应编码表
疫情期间居家办公的总结体会 |社区征文
XSS笔记(下)