20200806——JVM JMM

压缩指针的引入

32位的操作系统可以寻址2的32次幂 = 4g
64的操作系统可近似于无限大

一个对象会占的字节数

在java中基本数据类型有8种
boolean 1

char 2

byte 1
short 2
int 4
long 8

float 4
double 8

那么一个引用类型对象呢
在32位地址中,一个引用类型对象是占4字节的,引用类型要去方法区中去找类信息。同理64位地址中,占8字节。
那么就提及到了压缩指针,64位操作系统中开启 UseCompressedOops时,占用4字节,否则是8字节

JMM

java memory model一共由三部分组成
对象头 实例数据 填充字段

对象头

在32位系统中,占用8字节,markword 4字节 + kclass 4字节
在64位系统中,占用16字节,markword 8字节 + kclass 8字节
但是在64位系统中,如果使用了压缩指针,UseCompressedOops,只占用12字节,kclass缩短到了4字节。

实例数据是最开始提到的八种基本数据类型

填充头

如果字节不满足8的倍数,填充头会填充到8字节的倍数。

举个列子

class A{
	int a,
  	B b,
}

32位操作系统中
对象头(markdown 4字节+ kclass4字节)+实例数据 int类型4字节,引用类型B 4字节 = 16字节 无填充部分。

64位操作系统中
对象头(8+8) + 4+ 8 = 28字节 在填充到32字节。

64位如果开启压缩指针的话,kclass可以变成4字节。所以整体变成了24字节,不再需要填充部分。

可以减缓堆空间的压力(同样的内存空间,更不容易发生oom)

压缩指针是如何实现的

不再保存所有引用,而是每隔8个字节保存一个引用。例如,原来保存每个引用0、1、2…,现在只保存0、8、16…。因此,指针压缩后,并不是所有引用都保存在堆中,而是以8个字节为间隔保存引用。

在实现上,堆中的引用其实还是按照0x0、0x1、0x2…进行存储。只不过当引用被存入64位的寄存器时,JVM将其左移3位(相当于末尾添加3个0),例如0x0、0x1、0x2…分别被转换为0x0、0x8、0x10。而当从寄存器读出时,JVM又可以右移3位,丢弃末尾的0。(oop在堆中是32位,在寄存器中是35位,2的35次方=32G。也就是说,使用32位,来达到35位oop所能引用的堆内存空间)

哪些信息会被压缩

对象头的全局静态变量(即类变量)
对象头信息,64位操作系统,原生对象头大小16字节,压缩后位12字节
对象引用类型:64位平台下,引用类型本身大小位8字节,压缩后为4字节。
对象数组类型:64位平台下,数组类型大小本身为24字节,压缩后为16字节。

哪些信息不会被压缩

指向非heap的对象指针
局部变量,传参,返回值,null指针

你可能感兴趣的:(java杂谈,jvm)