1.请解释以下对象的创建过程?(半初始化)
在汇编层面,会先new出对象,但是对于变量会先赋默认值,然后在赋定义的值。存在一个半初始的状态。
2.DCL与volatile问题。(volatile指令重排)
DCL:单列模式中的双重检查锁。但是在实例对象上必须加上volatile。因为不禁止指令重排,可能会造成获得办初始化状态的对象。(volatile禁止指令重排通过内存屏障实现)。(volatile可见性原理:缓存一致性)
3.对象在内存中的存储布局?(对象和数组不同)
对象:对象头(markword 8字节、class pointer 4字节)、实例数据(instance data)、对齐(padding,补齐能被8整除)
数组:因为数组长度是固定的,所以创建时就会向内存申请空间。对象头(markword 8字节、class pointer 4字节)、数组长度(length 4字节)、实例数据(instance data)、对齐(padding,补齐能被8整除)
4.对象头具体包括什么?(markword classpointer synchronized锁信息)
对象头包含信息:
1.锁信息。无锁态001,偏向锁101(无锁态和偏向锁根据第三位判断),自旋锁00(轻量级锁,无锁,lock-free,CAS是在用户态实现的),重量级锁10(内核态的等待队列,不占用CPU),GC标记信息11(CMS过程用到的标记信息)
2.GC的分代年龄。4bit 最大值2^4 0~15.
3.hashcode 31位
5.对象怎么定位?(句柄方式,直接指针)
1.句柄方式。2个指针,实例数据指针指向对象,类型数据指针指向方法区 T.class,两次寻址才能确定对象。优点便于GC回收。
2.直接指针。直接指向堆中的对象,对象里面有类型数据指针指向方法区的 T.class。
6.对象怎么分配?(栈-线程本地-eden-old)
栈上(标量替换,逃逸分析)存储在栈上,POP或者线程销毁时-end。如果不能放栈上,判断对象是否很大
1.如果很大存储old老年代。老年代经过full GC - end。
2.如果不大,-TLAB(线程本地分配)。分配到年轻代,如果能在线程栈上存下就放线程栈,如果不行就进入年轻代eden。
年轻代的对象经过GC,如果被回收-end。如果不能被回收,进入survivor的TO区。然后循环,再次被GC,如果任然没有被回收,age+1,进入survivor的from区,from和to逻辑兑换,如此反复,直到对象age年龄达到,进入old区。(PS+PO的垃圾回收器 默认age 15,CMS 默认 6)
7.Object o = new Object()在内存中占用多少字节?
hotspot有压缩机制。压缩类指针(-XX:+UseCompressedClassPointers ),
压缩对象指针(-XX:+UseCompressedOops)。
对象引用4个字节。(O,String)
markword 8个字节
classpointer 4个字节
实例数据 0
对齐 4字节 压缩情况下24字节。默认压缩。
4个字节的寻址能力:32G堆内存 所以内存大于32G之后默认不压缩,所以48G的内存不一定存的东西比32G多。