JVM面试题
JVM面试题
什么是程序计数器?
程序计数器是线程私有的,每个线程一份,内部保存字节码的行号。用于记录正在执行的字节码指令的地址
介绍一下Java堆
堆内存是线程共享的区域:主要用来保存对象实例、数组等,内存不够则抛出OutOfMemoryError
异常
组成:年轻代+老年代组成
- 年轻代被分为三个部分:伊甸园区和两个大小Survivor区
- 老年代主要用来保存生命周期长的对象,一般是老的对象
Jdk1.7和1.8的区别
- 1.7中有一个永久代,存储的是类信息、静态变量、常量、编译后的代码
- 1.8移除了永久代,吧数据存储到了本地内存的元空间中,防止内存溢出
栈内存
什么是虚拟机栈
- 每个线程运行时所需要的内存称为虚拟机栈
- 每个栈由多个栈帧组成,对应着每次方法调用时所占用的内存
- 每个线程只有一个活动栈帧,对应着当前正在执行的那个方法
垃圾回收是否涉及栈内存
垃圾回收主要指的是堆内存,当栈帧弹出后,内存自动释放
栈内存越大越好吗
未必,默认的栈内存为1024k,栈帧过大导致线程数变少
方法内的局部变量是否线程安全?
- 如果方法内局部变量没有逃离方法的作用范围,它是线程安全的
- 如果局部变量引用了对象,并逃离方法的作用范围需要考虑线程安全问题
什么情况下会导致栈内存溢出?
- 栈帧过多 例如:递归调用
- 栈帧过大导致内存溢出
堆栈的区别是什么?
- 栈内存一般用来存储局部变量和方法调用,堆内存用来存储Java对象和数组。碓需要GC垃圾回收,栈不需要
- 栈内存是线程私有的,堆内存是共有的
- 异常错误不同:
- 栈内存不足:java.lang.StackOverFlowError
- 堆内存不足:java.lang.OutOfMemoryError
方法区
解释一下方法区
- 方法区是各个线程共享的内存区域
- 主要用来存储类的信息、运行时常量池
- 虚拟机启动的时候创建,关闭的时候释放
- 方法区的内存无法满足分配请求则会抛出OutOfMemeoryError:Metaspace
介绍一下运行时常量池
常量池:可以看作一张表,虚拟机指令根据这张表找到要执行的类名、方法名、参数类型、字面量等信息
当类被加载,它的常量池信息就会放入运行时常量池,并把里面的符号地址变为真实地址
类加载器
什么是类加载器,类加载器有哪些?
JVM只会运行二进制文件,类加载器的作用就是将字节码文件加载到JVM中,从而让java程序能够启动起来
- 类加载器包括四种
- 启动类加载器 加载核心类库
- 扩展类加载器 加载/jre/lib/ext下的拓展类文件
- 应用类加载器 加载classpath下的字节码文件
- 自定义加载器
什么是双亲委派机制?
加载一个类,先委托上一级的加载器进行加载,如果上级加载器也有上级,则会继续向上委托,如果该类委托上级没有加载成功,则子加载器尝试加载该类
为什么要使用双亲委派机制?
- 通过双亲委派机制可以避免一个类被重复加载,当父类已经加载后则无需重复加载,保证唯一性
- 为了安全,保证类库API不会被修改
*类加载器的执行流程
类加载器的执行流程共分为7个阶段
- 加载:查找和导入class文件
- 验证:保障加载类的正确性
- 准备:为类变量分配内存并设置类变量的初始化值 (static修饰的变量)
- 解析:把类中的符号引用转为直接引用
- 初始化:对类的静态变量、静态代码块执行初始化操作
- 使用:JVM开始从入口方法执行用户的程序代码
- 卸载:当用户程序代码执行完毕后,JVM开始销毁创建的Class对象
对象什么时候可以被垃圾回收器回收
如果一个或多个对象没有任何的引用指向它了,那么这个对象就是垃圾,如果定位了垃圾则可能被垃圾回收器回收
定位垃圾的方法
- 引用计数法 有循环引用问题
- 可达性分析算法
- 扫描堆中的对象,看是否能够沿着GC root对象为起点的引用链找到该对象,找不到则可以回收
哪些对象可以作用GC root
?
- 虚拟机栈中引用的对象
- 方法区中类静态属性引用的对象
- 方法区中常量引用的对象
- 本地方法栈JNI(Native方法)引用的对象
JVM
垃圾回收算法有哪些?
标记清除算法
垃圾回收分为两个阶段,分别是标记和清除,效率高,有磁盘碎片,内存不连接
标记整理算法
和标记清除一样,将存活的对象都向内存的另一端移动,然后清理边界以外的垃圾,无碎片,对象需要移动,效率低,一般老年代使用
复制算法
将原有的内存空间一分为二,每次只用其中一块,正在使用的对象复制到另一个内存空间中,然后该内存清空,交换两个内存的角色,完成垃圾回收:无碎片,内存使用效率低
说一下JVM中的分代回收
堆的区域划分
- 堆被分为了两份:新生代和老年代 1:2
- 新生代又被分为三个区域,Eden区,幸存者区(from和to)8:1:1
对象分代回收策略
-
新对象的创建都会被分到eden区
-
伊甸园区内存不足时,标记伊甸园区和from区中的存活对象
-
将存活对象复制到to中,复制完成后伊甸园区和from区的内存都会得到释放
-
经过一段时间后伊甸园区的内存又出现不足,标记eden区域to区域存活的对象,将其复制到from区
-
当幸存区的对象熬过几次回收(最多15次),晋升到老年代(幸存者区不足或者大对象都会提前晋升)
MinorGC、Mixed GC、FullGC的区别是什么?
- MinorGC(yiung GC)发生在新生代的垃圾回收,暂停时间短(STW)
- Mixed GC 新生代+老年代部分区域的垃圾回收,G1独有
- Full GC 新生代+老年代完整垃圾回收,暂停时间长(STW),应尽力避免
三色标记法是什么?
在CMS垃圾回收器中采用三种颜色表示对象被扫描的状态
- 白色:表示对象尚未被垃圾回收器访问过(分析结束阶段表示不可达)
- 灰色:表示对象已经被垃圾回收器访问过,但对象至少存在一个引用没有被扫描
- 灰色表示对象以及引用都被扫描过了
三阶段
初始标记阶段:将GC Roots直接关联的对象进行标记为灰色
并发标记阶段:扫描整个引用链,没有字节点直接将当前节点标为黑色,有字节点的将当前节点变为黑色,子节点变为灰色
重复并发标记阶段:确认灰色节点没有子节点后将节点标记为黑色,然后进行清除
JVM有哪些垃圾回收器?
- 串行垃圾回收器:Serial GC、SerialOld GC
- 并行垃圾回收器:Parallel Old GC、ParNew GC 默认
- CMS(并发)垃圾回收器
- G1:作用在新生代和老年代
聊一下G1垃圾回收器
- 应用于新生代和老年代,在JDK9之后默认使用G1
- 将内存划分为多个大小相等的区域,每个区域都可以充当eden、survivor、old、humongous,其中humongous专门为大对象准备
- 采用复制算法
- 响应时间和吞吐量兼顾
- 分为三个阶段:新生代回收(stw)、并发标记(重复标记stw)、混合收集
- 如果并发失败(回收速度赶不上对象创建速度)会触发FullGC
<