一.请简述对象的创建过程
对象的new字节码执行指令如下图
首先0指令new出一片内存空间,然后进行对象的初始化,初始化完成前变量都是初始值如m=0
然后创建连接,t指向对象。
二.DCL单例要不要加volatile?
DCL单例就是要懒汉式从创建单例对象,通过双重检查锁的方式
DCL (Doouble Check Lock)双重检查锁
单例 设计模式
一定要加volatile 因为再创建对象过程中 要进行双重检查,第二次检查时对象发生指令重排就会造成没有进行完初始化,连接就完成了就会造成对象处于半初始化状态不为空,打破单例。
(cpu为什么进行指令重排?cpu的速度要比内存快好多,为了不发生等待优化系统指令内部进行的操作)
三.对象在内存中的布局
1.mrakword(8)(锁信息 hash信息 gc信息)和classpointer(4)共同构成对象头(objectheader)
对象是数组,那么额外增加4个字节存储数组的长度(4)
类型指针是指向方法去中的instenceklass(保存对象的全部数据)
对齐是虚拟机要求对象大小是8的倍数,所以需要补齐
通过JOL查看jvm信息
<dependency>
<groupId>org.openjdk.jol</groupId>
<artifactId>jol-core</artifactId>
<version>0.9</version>
</dependency>
public class Test01 {
public static void main(String[] args) {
Object o = new Object();
System.out.println(ClassLayout.parseInstance(o).toPrintable());
}
}
四.对象是怎么定位
五.对象是怎么分配的 (TLAB线程本地缓冲区)
六.类的加载
首先类的加载经过三个主要阶段,加载连接初始化
其中连接又分为验证,准备,解析三个阶段
首先是java采用了oop-klass模型表示java对象,
在类的加载阶段会创建一个instanceklass对象存放在方法区中,
这里的方法区是抽象概念不同的jdk版本有不同的实现
主要保存的是类的元信息,同时会创建instancemirrorklass对象
存放在堆区,用于反射,这个对象成为镜像,虚拟机不会将instanceklass对象暴露给java
而是利用他的镜像创建对象,创建的对象指向instanceklass,因为互相指向所以能够获取镜像
验证阶段主要是验证元数据,字节码文件等
准备阶段进行静态变量的内存分配以及初始化
解析阶段将其间接引用变为直接引用,符号引用对象B,这时就会触发B的加载变为直接引用
初始化阶段执行静态代码块,静态变量的真正赋值