Java Memory Model (JMM)
一、对象的创建过程
首先类如果没有加载的话先进行加载,包括3个步骤:
1、class loading,将class加载到内存;
2、class linking,校验,将类的静态变量赋默认值,解析;
3、 class initializing,静态变量赋初始值,并执行静态代码块
然后创建对象:
1、申请对象内存
2、成员变量赋默认值
3、调用构造方法:将成员变量按顺序赋初始值,执行构造方法,首先要调用super构造方法。
二、对象布局
普通对象和数组对象的对象布局不同。
1、普通对象
1)对象头,markword,8个字节
2)ClassPointer 指针,-XX:+UseCompressedClassPointers 开启压缩为4个字节,不开启压缩为8个字节
3)实例数据,其中引用类型 -XX:+UserCompressedOops (Ordinary Object Pointers)开启压缩的话为4个字节,不开启压缩为8个字节,其他类型根据类型而定
4)Padding 对齐,8的倍数
2、数组对象
1)对象头,markword,8个字节
2)ClassPointer 指针,开启压缩为4个字节,不开启压缩为8个字节
3)数组长度,4个字节
4)数组数据
5)Padding 对齐,8的倍数
三、对象大小
所以new Object()大小是多少?
对象头,8个字节;ClassPointer指针,4或8个字节,如果4个字节,Padding补齐成8的倍数,所以总大写为8+4+4或者8+8=16个字节。
new int[] {} 大小是多少?
对象头,8个字节;ClassPointer指针,不开启压缩8个字节;数组长度4个字节;数据空;Padding补齐成8的倍数;总大小应该是8+8+4+4=24;如果开启压缩,8+4+4 = 16。
new M() 大小是多少?
class M {
// 对象头,8个字节
// ClassPointer 指针,开启压缩4个字节,不压缩8个字节,通过-XX:+UseCompressedClassPointers开启起作用
int i; //4个字节
String s; //引用类型,开启压缩4个字节,不压缩8个字节
byte b; //1
Object o; // 引用类型,开启压缩4个字节,不压缩8个字节;通过-XX:+UserCompressedOops开启压缩起作用
}
三、对象头组成
markword,在对象处于不同状态下存储的内容不同,比较复杂。对于64位的而言,根据锁状态具体如下:
1)无锁态,2位锁标志位01;1位是否偏向锁固定为0;是引用25位存储对象的hashCode,4位存储分代年龄。
2)轻量级锁,2位锁标志位00,另外存储指向栈中锁记录的指针
3)重量级锁,锁标志位为10,以及指向互斥量的指针
4)GC标记,11锁标志位
5)偏向锁,01锁标志位,是否偏向锁1位固定为1,另外包含线程ID,Epoch,分代年龄。
四、对象定位
对象定位有两种,句柄池和直接指针。
句柄池,通过间接指针,例如t = new T(),指向两个指针,一个指向对象,另一个指向t.class。
直接指针,直接指向对象。Hotspot 使用的是这种,效率比较高,可以直接找到对象。