JVM面试题
1、请解释以下对象的创建过程(半初始化)
- 申请内存
- 设初始值
- 建立关联
2、双重检查锁定DCL(Double Check Lock)单例需不需要volatile?(指令排序)
先说答案:要加;
要是想模拟多线程情况进行测试,很难出问题(需要很高的并发量);
volatile的两个作用:
- 保证线程可见性
- 禁止指令重排序
如果不加,线程1可能先建立连接、后赋值,那么线程2同时取这个值就会出问题;
volatile的实现原理是内存屏障。
3、对象在内存中的存储布局?(对象与数组的存储不同)
普通对象:
基于执行效率的考虑,对象的大小要是8字节的整数倍;其中markword占8字节、class pointer占4字节、实例数据看具体情况、对齐用来补充使对象的大小是8字节的整数倍。
数组:
4、对象头具体包括什么?(markword classpointer)synchronized锁信息
这一块涉及到锁升级的过程
在jdk1.0的时候,synchronized是重量级的锁,每一次申请资源都需要通过操作系统(OS)来进行,特别耗费资源。
如今,在jdk1.8,synchronized进行了不断地优化,变得更加高效,涉及到锁升级的过程,而markword当中装了锁的信息。
锁升级过程
无锁–>偏向锁–>自旋锁–>重量级锁,所只能升级,不能降级;
- 无锁:没有对资源进行锁定,所有的线程都能访问并修改同一个资源,但同时只有一个线程能修改成功,此时偏向锁标志位为0;
- 偏向锁:此时仅有一个线程访问资源(无锁竞争的情况),偏向锁标志位为1,记录线程的ID;
- 自旋锁:又称轻量级锁,原理是CAS,CAS 利用 CPU 指令保证了操作的原子性,如果有线程竞争就会升级为自旋锁;
- 重量级锁:自旋十次后,升级为重量级锁;
ABA问题
为了解决ABA问题,JDK为提供了AtomicMarkableReference和AtomicStampedReference类来解决这个问题。其中,AtomicStampedReference是利用版本戳的形式记录了每次改变以后的版本号。
对象头中的markword
5、对象怎么定位?(直接、间接)
JVM使用的是直接指针的方式
还有一种是句柄方式
它的唯一好处就是:对象小,垃圾回收时不用频繁改动t
方法区
《Java 虚拟机规范》只是规定了有⽅法区这么个概念和它的作⽤,并没有规定如何去实现
它。那么,在不同的 JVM 上⽅法区的实现肯定是不同的了。 ⽅法区和永久代的关系很像
Java 中接⼝和类的关系,类实现了接⼝,⽽永久代就是 HotSpot 虚拟机对虚拟机规范中⽅
法区的⼀种实现⽅式。 也就是说,永久代是 HotSpot 的概念,⽅法区是 Java 虚拟机规范中
的定义,是⼀种规范,⽽永久代是⼀种实现,⼀个是标准⼀个是实现,其他的虚拟机实现并
没有永久代这⼀说法。JDK1.8取消了永久代,改为元空间。