-
创建一个Java对象A的底层顺序
- 检查类A是否已经被加载(方法区)
- 执行类加载、解析、初始化
- 为新生对象分配内存空间
- 将分配的内存空间初始化为零值,基础对象赋值为默认值,引用对象赋值为null
- 调用对象的ini方法,static代码块
-
创建一个Java对象的底层步骤细节
-
虚拟机遇到一条new指令的时候,首先检查这个对应的类能否在常量池中定位到一个类的符号引用(是否在常量池中存在)
-
判断这个类是否已经被加载、解析和初始化
-
为这个新对象在Java堆中分配内存空间、其中Java堆分配内存空间的主要方式有以下两种
-
指针碰撞
-
分配内存空间包括开辟一块内存和移动指针两个步骤
-
非原子步骤可能出现并发问题,Java虚拟机采用CAS配上失败重试的方法保证更新操作的原子性
-
-
空闲列表
- 分配内存空间包括开辟一块内存和修改空闲列表两个步骤
- 非原子步骤可能出现并发问题,Java虚拟机采用CAS配上失败重试的方式保证更新操作的原子性
-
-
将分配到的内存都初始化为零值
-
设置对象头相关数据(GC分代年龄、对象的哈希码HashCode、元数据信息)
-
执行对象ini方法(静态代码块)
-
-
Java对象内存布局
- 对象头Header,对象头用于存储对象的元数据信息,包括对象运行时数据和类型指针
- Mark Word部分存储对象自身的运行数据如哈希值、GC分代年龄、锁状态标识、线程持有的锁、偏向锁ID、偏向锁时间戳
- 类型指针指向它的元数据的指针、用于判断对象属于哪个类的实例
- 实例数据Instance Data,实例数据存储的是真正的有效数据
- 如各种字段内容、父类定义的变量会出现子类定义的变量的前面
- 对齐填充Padding
- 对其填充部分仅仅起到占位符的作用,并非必须
- 对象头Header,对象头用于存储对象的元数据信息,包括对象运行时数据和类型指针
-
访问对象的定位方式
- 直接指针访问:局部变量表中存放的对象的指针,可以直接定位堆里面的对象的实例数据,堆中对象的类型数据执行方法区的对象的类型数据。
- 句柄访问:在堆里面开放一块内存用来存放句柄池, 存放对象类型的指针和对象实例的指针
-
两者的指针
- 垃圾回收分析:方式2当垃圾回收移动对象时,reference中存储的地址是稳定的地址,不需要修改,仅需要修改对象句柄的地址;方式1垃圾回收时需要修改reference中存储的地址
- 访问效率分析:方式1由于方式2,因为方式2只进行了一次指针定位,节省了时间开销,而这也是HotSpot采用的实现方式。
深入浅出JVM之Java对象
最新推荐文章于 2022-01-12 09:59:08 发布