阿里P8的这点Java底层?-对象的大小、指针压缩

文章开头思考一个问题:为什么要计算对象大小

对象的大小

对象的内存布局

阿里P8的这点Java底层?-对象的大小、指针压缩_第1张图片

对象头

  • Mark Word
    32位机,占4字节;64位机,占8字节。
    主要存储对象运行时的一部分数据: hashcode,GC 分代年龄,锁状态标志位,线程锁标记,偏向线程ID,偏向时间戳等
  • 类型指针(Klass point)
    指向方法区当前对象的Class类
    开启指针压缩:指针大小为4B;未开启指针压缩:指针大小位8B
  • 数组长度
    普通对象没有数组长度,数组对象才有数组长度
  • 对齐填充(上第二个图,特殊情况下会有,见下面数组对象的演示)
    数组对象在关闭指针压缩时,对象头会有填充

实例数据

对齐填充

JVM中所有对象大小都按8字节倍数对齐,填充的那部分就是填充

巩固上述内容,现在看一下空对象的大小
空对象:没有任何普通属性的类生成的对象

  • 开启指针压缩 16B
    =8B(Mark Word) + 4B(Klass point) + 0B(数组长度) + 0B(实例数据) + 4B(对齐填充)
  • 未开启指针压缩 16B
    =8B(Mark Word) + 8B(Klass point) + 0B(数组长度) + 0B(实例数据) + 0B(对齐填充)

指针压缩(优化)

开启(默认)/关闭指针压缩 -XX:+/-UseCompressedOops

目的

通常64位JVM消耗的内存会比32位的大1.5倍,这是因为对象指针在64位架构下,长度会翻倍(更宽的寻址)。
对于那些将要从32位平台移植到64位的应用来说,多了1/2的内存占用
节省空间,提升jvm运行效率

指针压缩效果对比(注意区分对象的内存组成)

  • 空对象
    阿里P8的这点Java底层?-对象的大小、指针压缩_第2张图片
  • 普通对象
    阿里P8的这点Java底层?-对象的大小、指针压缩_第3张图片
  • 数组对象
    阿里P8的这点Java底层?-对象的大小、指针压缩_第4张图片
    注意上例数组对象关闭指针压缩时,出现了两个alignment(对齐填充),为什么会有两个???

指针压缩实现原理

调优参数

-XX:+/-UseCompressedOops(默认开启指针压缩)
oop:普通对象指针(ordinary object pointer),注意不是OOP(面向对象)

指针压缩原理

未开启指针压缩时,指针长度为8B,寻址单位是1B。
通过上文我们得知,jvm中对象的大小都是按8B对齐的,这能让我们有什么想法?
为什么我们不能将寻址单位扩大为对齐单位呢(想想,对齐单位的大小能调整吗?
开启指针压缩时,指针长度为4B,寻址单位是8B(默认)
!!!!!希望能找到open jdk的实现逻辑来佐证一下,立个flag!!!!!!

思考1:开启指针压缩时,指针最大能表示的堆空间大小是多大?
指针压缩:指针8B长度(1B/单位) -> 4B长度(8B/单位)

  • 8B长度指针支持的寻址内存大小是?

8B * 8bit/B = 64bit 寻址长度
2^64 * 1B ??操作系统的寻址位只用了48位,最大支持2^48的寻址单位,jvm能超了这个?疑问?同上,有时间找open jdk源码看一下吧,这里有个flag
反正支持的寻址内存很大!

  • 4B长度指针支持的寻址内存大小是?

4B * 8bit/B = 32bit 寻址长度
2^32 * 8B = 32GB (32位操作系统支持最大4G内存,其寻址单位是1B,这里的单位是8B,那这里当然就是8*4G了)
哎呀,开启了指针压缩,堆支持的大小还变小了??

思考2:开启指针压缩时,若将堆内存大小设置成32G,会发生什么?
java -Xmx32g -XX:+PrintFlagsFinal hzw | grep -e UseCompressed 和下图命令同效果,因为默认开启指针压缩
在这里插入图片描述

上图除了Oop压缩以外,还发现一个ClassPointers?(普通对象指针和类指针)

什么现象?堆内存分配大于32G时,指针压缩设置失效了?为什么呢?
哈哈,我也不知道,我猜有两点
a. 8B指针寻址方式,内存范围更大,能超过32G;
b. (瞎猜)指针压缩的目的是防止新生代担保到老年代,从而导致频繁的fullGC。那你想想,这堆都分配了32G了,家里有钱何必再抠搜搜省这么点空间?

思考3:思考一下,能否通过开启指针压缩,然后扩大补齐单位从8B到16B,实现内存扩容支持?
我也不清楚了,就是有这个疑问(待确认)!
若扩大的补齐单位到16B的话,指令压缩支持内存是不是就能扩展到64G了,是否有jvm的参数控制这个?

》》为什么要计算对象大小

内存调优,一般是调整堆空间。堆空间里放的是对象,若要保证堆不频繁的进行Full GC,就要控制老年代的大小。
新生代占用过高时,容易发生内存担保,发生担保时新生代对象转移到老年代。
要防止新生代中的对象担保到老年代中,所以需要计算对象的大小并加以优化

内存担保概念在“阿里P8的这点Java底层?-JVM内存模型”中有提及

你可能感兴趣的:(java)