前言
这是一篇看了能说的进去的 jvm 面试;集体能力无限,文中形容不免有谬误,请斧正;
一 JVM 面试
1.1 简述 Java 内存模型(重点)
jvm 会将运行程序所治理的空间分为若干局部,每个局部都起到至关重要的局部;jdk1.8java 运行时数据区如下:
程序计数器
:以后线程执行字节码的行号指示器;字节码解析器通过扭转计数器的值,来选取下一条须要执行的字节码指令,分支、循环、跳转、异样解决、线程复原等根底性能;
Java 虚拟机栈
: java 办法执行的内存模型,每个办法被执行的时候都会创立帧栈用于存储局部变量表、操作数栈、动静链接、办法进口等信息;
本地办法栈
: 执行 java 的 native 办法服务,每个办法被执行的时候都会创立帧栈用于存储局部变量表、操作数栈、动静链接、办法进口等信息;
Java 堆
: 贮存对象的实例和数组;
办法区
: 非堆,贮存类的构造信息;例如运行时常量池的字段和办法数据,构造函数和一般办法的字节码内容等;
科普运行时罕用池:运行时罕用池是 class 文件中每一个类或者接口的常量池表的运行表现形式,包含若干种常量,如字段和办法的援用;在类加载至虚拟机的时候就会创立运行时常量池;
科普帧栈:帧栈用于贮存数据和局部过程后果的数据,同时也会解决动静链接,办法返回值和分派;帧栈随着办法的创立而创立,随着办法的销毁而销毁;帧栈中保护着本地变量表,操作数栈,和指向以后办法所属类的运行常量池的援用;
留神:jdk1.8 曾经应用元空间代替了 jdk1.7 办法区中的永恒代,元空间存在于 native 内存中, 其大小依据本地内存而定,没有限度;具体看官网地址
https://docs.oracle.com/javase/8/docs/technotes/guides/vm/gctuning/considerations.html#sthref66
1.2 简述类的加载过程(重点)
类的加载过程分为 加载,链接,初始化,应用,和卸载 5 个阶段,其中连贯阶段又分为验证 筹备和解析阶段;
- 加载阶段:次要是取得类的二进制字节流在内存中生产 Class 对象;
- 连贯阶段:验证 Class 的安全性,合乎虚拟机标准;筹备类的内存调配和初始化变量;解析常量池的符号援用(将符号援用转换为间接援用);
- 初始化阶段:对动态变量和动态代码赋初值;
- 应用阶段;
- 卸载阶段;
1.3 哪些地方会产生 OOM?
内存溢出:申请了 8 个字节的空间,然而你在这个空间写入 9 或以上字节的数据,呈现内存溢出;
在 java 内存模型中只有程序计数器不会产生 OOM(out of memory),其余地区都会产生 OOM;
1.4 什么是双亲委派模型?
当一个类收到了类加载申请时,本人不会先去加载这个类,而是将其委派给父类去加载,如果父类不能加载,反馈给子类,由子类去实现类的加载;
这边有可能会问,你都晓得哪些类加载器:
- 启动类加载器:次要加载 %JAVA_HOME%\lib 目录下的类库文件或者 -Xbootclasspath 所指定的类库文件(加载外围类)
- 扩大类加载器:次要加载 %JAVA_HOME%\lib\ext 目录下的类库文件或者 java.ext.dirs 零碎变量所指定的类库文件(加载扩大库)
- 程序利用类加载器:次要加载用户类门路 (classpath) 所指定的类库。
- 用户自定义类加载器:加载用户自定义的类库。
如何突破双亲委派模型?
双亲委派模型都依附 loadClass()
,重写loaderClass()
即可;
1.5 新生代中辨别 Eden 和 Survivor 的作用是什么
新生代分为 3 个分区:Eden(伊甸园)、Survivor1、Survivor2;其中 Survivor1、Survivor2 合起来成为 Survivor(幸存区); 如果没有 Survivor,Eden 区每进行一次 Minor GC
,存活的对象都会被送到老年代。老年代将很快被填满,老年代每产生一次Full GC
的速度比 Minor GC
慢 10 倍;
Survivor 的作用就是缩小老年代
Full GC
的次数, 相当于缓冲带;Eden 和 Survivor 的比例调配 8:1;
1.6 简述分代垃圾回收器工作流程
- 泛滥的对象都调配在 Eden;
- 一个 survivor 空间接管来自 Eden 存活的对象;
- 2 个 survivor 空间的对象会互相复制,不论 survivor 空间的对象如何复制,总有一个 survivor 空间是空的用于接管来自 Eden 存活的对象;
- 当 survivor 空间有余时,对象就会复制到老年代;
官网:
https://docs.oracle.com/javase/8/docs/technotes/guides/vm/gctuning/generations.html#sthref16
1.7 简述内存调配与回收策略(重点)
- 大多数状况下对象都优先间接调配在 Eden , 当 Eden 空间有余时会产生 Minor GC, 每通过一次 Minor GC,年龄 +1,若年龄超过 15,则被进入到老年态。当老年代空间有余时就会产生 Full GC;
- 长期存活对象将进入老年代
- 如果是大对象 (须要大量间断内存空间的对象) 间接进入老年代;
会呈现的小问题就是:Minor GC 和 Full GC 触发条件,答默认状况下产生 15 次 Minor GC 之后就会触发一次 Full GC
1.8 GC 是什么? 为什么要有 GC?
GC 是垃圾收集(GabageCollection);Java 提供的 GC 性能能够主动监测对象是否超过作用域从而达到主动回收内存的目标,而不须要人为手动开释内存;次要调用的是 System.gc() 和 Runtime.getRuntime().gc();
1.9 简述 CMS 收集器
CMS(Concurrent Mark Sweep)收集器基于 标记—革除算法
实现的收集器,是一种以获取最短回收进展工夫为指标的收集器。次要长处是并发收集,低进展,在 cpu 多核的状况下性能较好。在启动 JVM 的参数加上
“-XX:+UseConcMarkSweepGC”来指定应用 CMS 垃圾回收器;其应用在老年代 能够配合新生代的 Serial 和 ParNew 收集器一起应用;因为 CMS 应用 标记—革除算法
GC 时会产生大量碎片,有可能提前触发 Full GC;如果在老年代充斥之前无奈回收不可达对象,或者没有足够的空间满足调配就会导致 Concurrent Mode Failure(并发模式故障);
官网:
https://docs.oracle.com/javase/8/docs/technotes/guides/vm/gctuning/cms.html
2.0 简述 G1 收集器
G1(Garbage-First)从整体来看是基于 标记—整顿
算法实现的收集器,可能实现并发并行,对 cpu 利用率较高,缩小进展工夫。指标是取代 jdk1.5 公布的 CMS 收集器。G1 收集器收集范畴是 老年代和新生代
,不须要联合其余收集器应用,G1 收集器可预测垃圾回收的进展工夫, 对空间进行整合;因为 G1 是基于复制算法实现,当没有足够的空间(region)调配存活的对象就会导致 Allocation (Evacuation) Failure(调配失败);
官网:
https://docs.oracle.com/javase/8/docs/technotes/guides/vm/gctuning/g1_gc.html#garbage_first_garbage_collection
2.1 jvm 调优时如何抉择垃圾回收器(重点)
- 当利用的数据集较小时,约 100M 时或者 单线程利用,没有严格的进展要求抉择 serial 收集器;参数选项:-XX:+UseSerialGC;
- 如果对利用的性能要求高或者没有进展要求,能够承受 1 秒或者更久的进展抉择 parallel 收集器;参数选项:XX:+UseParallelGC;
- 如果对响应工夫有很高的要求相比于吞吐量,谋求更小的进展工夫能够应用 CMS 或者 G1;参数选项:-XX:+UseConcMarkSweepGC 或者 XX:+UseG1GC
官网:
https://docs.oracle.com/javase/8/docs/technotes/guides/vm/gctuning/collectors.html#sthref27
2.2 简述 GC 中 Stop the world(重点)
Java 中 Stop-The-World 机制简称 STW,是在执行垃圾收集算法时,Java 应用程序的其余所有线程都被挂起。Stop-The-World 对系统性能存在影响,因而垃圾回收的一个准则是尽量减少“Stop-The-World”的工夫;
2.3 垃圾回收算法(重点)
标记 - 革除法
:标记出没有用的对象,之后一个一个回收掉
- 毛病:标记和革除两个过程效率不高,产生内存碎片导致须要调配较大对象时无奈找到足够的间断内存而须要触发一次 GC 操作;
- 长处:实现简略;
复制算法
: 依照容量划分二个大小相等的内存区域,当一块用完的时候将活着的对象复制到另一块上,而后再把已应用的内存空间一次清理掉
- 毛病:将内存放大为原来的一半;
- 长处:按程序分配内存,实现简略、运行高效,不必思考内存碎片。
标记 - 整顿法
:标记出没有用的对象,让所有存活的对象都向一端挪动,而后间接革除掉端边界以外的对象
- 长处:解决了标记 - 革除算法导致的内存碎片问题。
- 毛病:仍须要进行部分对象挪动,肯定水平上升高了效率。
分代回收
:依据对象存活周期的不同将内存划分为几块,个别是新生代和老年代,新生代根本采纳复制算法,老年代采纳标记整顿算法
2.4 你晓得哪些垃圾收集器
2.5 你有遇到过 java 内存透露么?(次重点)
内存透露:new 申请了一块内存,起初很长时间都不再应用了(按理应该开释),然而因为始终被某个或某些实例所持有导致 GC 不能回收;
经典案例
void test(){
Vector vector = new Vector();
for (int i = 1; i<100; i++)
{
Object object = new Object();
vector.add(object);
object = null;
}
//… 对 vector 的操作
//… 与 vector 无关的其余操作
}
手动解决赋值 null 即可
void test(){
Vector vector = new Vector();
for (int i = 1; i<100; i++)
{
Object object = new Object();
vector.add(object);
object = null;
}
//… 对 vector 的操作
vector = null;
//… 与 vector 无关的其余操作
}
还有各种流和 socket 的 close 办法未被调用也会产生内存透露问题;
2.6 对象什么时候会被 GC
- 援用计数器法:为每个对象创立一个援用计数,有对象援用时计数器 +1,援用被开释时计数 -1,当计数器为 0 时就能够被回收。它有一个毛病不能解决循环援用(A->B,B->A)的问题,那么 AB 将永远不会被回收;
- 可达性剖析算法:从 GC Roots 开始向下搜寻,搜寻所走过的门路称为援用链。当一个对象到 GC Roots 没有任何援用链相连时,则证实此对象是能够被回收的。
2.7 说下 Java 内存堆和栈区别(偶然会问到)
- 栈内存用来存储根本类型的变量和对象的援用变量,堆内存用来存储 Java 中的对象;
- 栈内存线程公有,堆内存线程共享
- 栈内存不足时,JVM 会抛出 java.lang.StackOverFlowError(个别产生在递归的时候);堆内存不足时,JVM 会抛出 java.lang.OutOfMemoryError
- 栈的内存远小于堆内存,-Xss 选项设置栈的大小。-Xms 选项能够设置堆的开始大小;
2.8 强援用、软援用、弱援用、虚援用以及他们之间和 gc 的关系
- 强援用:new 出的对象之类的援用,只有强援用还在,gc 时永远不会被回收
- 软援用:有用但非必须的对象,内存溢出异样之前,回收
- 弱援用:有用但非必须的对象,对象能生存到下一次垃圾收集产生之前。
- 虚援用:对生存工夫无影响,在垃圾回收时失去告诉。
2.9java 对象创立
- 应用 new 关键字创建对象; 会调用构造方法;
- 应用 Class 类的 newInstance 办法(反射机制);会调用构造方法;
- 应用 Constructor 类的 newInstance 办法(反射机制);会调用构造方法;
- 应用 Clone 办法创建对象;不会调用构造方法;
- 应用 (反) 序列化机制创建对象;不会调用构造方法;
3.0 如果对象的援用被置为 null,垃圾收集器是否会立刻回收对象?
不会,在下一个垃圾回收周期中回收对象。
3.1 jvm 调优工具又哪些?各自的作用又是什么(重点)
- jps: 查看过程的参数信息;
- jstat: 查看某个 Java 过程内的线程堆栈信息;
- jinfo: 查看虚拟机参数;
- jmap: 查看堆内存应用情况,生成快照存储(dump 文件);
- jhat: 剖析 jmap dump 生成的快照文件;
- jconsole: 基于 JMX 的可视化工具,监控 cpu, 内存,线程等应用状况;
- jvisualvm: JDK 自带剖析工具, 功能齐全,如查看进行信息,快照转存,监控 cpu, 线程,办法区,堆等;
3.2 你晓得哪些 JVM 调优参数
- -Xms128m JVM 初始调配的堆内存
- -Xmx512m JVM 最大容许调配的堆内存,按需分配;
- -XX:MetaspaceSize:调配给类元数据空间(以字节计)的初始大小;
- -XX:MaxMetaspaceSize:调配给类元数据空间的最大值,超过此值就会触发 Full GC
- -XX:NewRatio:新生代和老年代的占比;
- -XX:NewSize:新生代空间;
- -XX:SurvivorRatio:伊甸园空间和幸存者空间的占比;
- -XX:MaxTenuringThreshold:对象进入老年代的年龄阈值;
- XX:+PrintGC:打印 gc 信息;
- -XX:+PrintGCDetails:打印 gc 详细信息
如果你对文中的知识点不太了解 举荐浏览周志明学生《深刻了解 Java 虚拟机:JVM 高级个性与最佳实际(第 3 版)》和作者给出的官网链接!!!!