JVM相关的面试题

1.JVM的主要组成部分及其作用?
类加载器 ClassLoader:Java代码 -----> 字节码 的编译过程
运行时数据区:把上一步编译得到的字节码加载到内存中
执行引擎:命令解析器,解析上一步加载而来的字节码,翻译成为系统指令,交由CPU执行
本地库接口 Native Interface:诸如IO之类的由其他语言写成的本地库接口

2.JVM运行时数据区包含哪些?
程序计数器:行号指示器,通过改变该值,以选取下一步的指令
Java虚拟机栈:局部变量、方法出口等,为JVM服务
本地方法栈:局部变量、方法出口等,为本地Native方法服务
堆区:内存最大的一块,所有的对象实例都在这里分配内存
方法区:常量、静态变量等

3.堆栈的区别?
功能方面:堆存放对象,栈执行程序。
共享性:堆全线程可见,栈线程私有。
空间大小:堆内存远大于栈内存。

4.队列和栈的定义?以及区别?
预存储数据的一种数据结构。
队列先进先出:FIFO
栈后进先出:LIFO

5.双亲委派模型:
如果一个类加载器收到了类加载的请求,它首先不会自己去加载这个类,而是把这个请求委派给父类加载器去完成,每一层的类加载器都是如此,这样所有的加载请求都会被传送到顶层的启动类加载器中,只有当父加载无法完成加载请求(它的搜索范围中没找到所需的类)时,子加载器才会尝试去加载类。
加载器的顺序(先从下到上,再从上到下):
1. 启动类加载器:JVM的一部分,加载JAVA_HOME/lib目录下的类,或者是被-Xbootclasspath指定的类路径
2. 扩展类加载器:负责加载JAVA_HOME/lib/ext目录下的类,或者是被java.ext.dirs指定的类路径
3. 程序类加载器:负责加载classpath里的类。

Log4j配置文件加载的顺序(先log4.xml,后log4.properties):
1. 项目中的配置文件
2. 项目所引入的jar包中的配置文件
3. 项目classpath外挂出来的配置文件

Tomcat中class和jar的加载顺序:
1. $java_home/lib 目录下的java核心api
2. $java_home/lib/ext 目录下的java扩展jar包
3. java -classpath/-Djava.class.path所指的目录下的类与jar包
4. $CATALINA_HOME/common目录下按照文件夹的顺序从上往下依次加载
5. $CATALINA_HOME/server目录下按照文件夹的顺序从上往下依次加载
6. $CATALINA_BASE/shared目录下按照文件夹的顺序从上往下依次加载
7. 我们的项目路径/WEB-INF/classes下的class文件
8. 我们的项目路径/WEB-INF/lib下的jar文件

每个ClassLoader加载Class的过程是:
1.检测此Class是否载入过(即在cache中是否有此Class),如果有到8,如果没有到2
2.如果parent classloader不存在(没有parent,那parent一定是bootstrap classloader了),到4
3.请求parent classloader载入,如果成功到8,不成功到5
4.请求jvm从bootstrap classloader中载入,如果成功到8
5.寻找Class文件(从与此classloader相关的类路径中寻找)。如果找不到则到7.
6.从文件中载入Class,到8.
7.抛出ClassNotFoundException.
8.返回Class.

6.类装载的执行过程:
1. 加载:加载class文件到内存中
2. 检查:检查class文件有无错误
3. 准备:静态变量分配内存空间
4. 解析:静态变量的引用指向内存地址
5. 初始化:初始化成员变量等....

7.判断对象可回收:
1. 引用计数法:被引用,则计数器+1,当计数器为0时,回收对象。
2. 可达性分析:从当前对象到GC Root,没有任何引用链时,该对象即可回收。

8.Java中都有哪些引用类型:
强引用:发生gc时不会被回收
软引用:有用但不是必须的,内存溢出时会被清理
弱引用:有用但不是必须的,下次gc时会被清理
虚引用:无法通过虚引用获得对象,用 PhantomReference 实现虚引用,虚引用的用途是在 gc 时返回一个通知。

9.JVM的垃圾回收算法:
标记-清除:无用对象全部干掉
标记-整理:有用对象都向一边移动,边界以外的全部干掉
复制算法:左边内存快满时,将其中要保留的对象复制到右边内存中,然后整体干掉左边内存。右边同理,内存利用率仅有一半
分代算法:根据对象存活周期的不同将内存划分为几块,一般是新生代和老年代,新生代基本采用复制算法,老年代采用标记整理算法。

10.JVM的垃圾回收器:
重点需要关注CMS和G1两种。
CMS:一种以获得最短停顿时间为目标的收集器,非常适用 B/S 系统。
G1:一种兼顾吞吐量和停顿时间的 GC 实现,是 JDK 9 以后的默认 GC 选项。

11.CMS垃圾回收器
牺牲吞吐量为代价,获得最短的回收停顿时间。
要求服务器响应速度额应用上,最为适合。常用于B/S架构。
采用标记-清除算法实现,剩余内存无法满足要求时,会出现“Concurrent Mode Failure”,并采用Serial Old来单线程回收老年代内存。
解决和避免“Concurrent Mode Failure”的方法如下:
调小年轻代,适当调整老年代的回收阈值和GC频次,以保证年轻代数据置入过来时有足够空间可用。

12.新生代垃圾回收器和老生代垃圾回收器都有哪些?有什么区别?
• 新生代回收器: Serial、 ParNew、 Parallel Scavenge
• 老年代回收器: Serial Old、 Parallel Old、 CMS
• 整堆回收器: G1
新生代垃圾回收器一般采用的是复制算法,复制算法的优点是效率高,缺点是内存利用率低;
老年代回收器一般采用的是标记-整理的算法进行垃圾回收。

13.简述分代垃圾回收器是怎么工作的?
分代回收器有两个分区:老生代和新生代,新生代默认的空间占比总空间的 1/3,老生代的默认占比是 2/3。
新生代使用的是复制算法,新生代里有 3 个分区: Eden、 To Survivor、 From Survivor,它们的默认占比是 8:1:1,它的执行流程如下:
• 把 Eden + From Survivor 存活的对象放入 To Survivor 区;
• 清空 Eden 和 From Survivor 分区;
• From Survivor 和 To Survivor 分区交换, From Survivor 变 To Survivor, To Survivor 变 From Survivor。
每次在 From Survivor 到 To Survivor 移动时都存活的对象,年龄就 +1,当年龄到达 15(默认配置是 15)时,升级为老生代。大对象也会直接进入老生代。
老生代当空间占用到达某个值之后就会触发全局垃圾收回,一般使用标记整理的执行算法。以上这些循环往复就构成了整个分代垃圾回收的整体执行流程。

14.JVM 调优的工具?
JDK 自带了很多监控工具,都位于 JDK 的 bin 目录下,其中最常用的是 jconsole 和 jvisualvm 这两款视图监控工具。
• jconsole:用于对 JVM 中的内存、线程和类等进行监控;
• jvisualvm: JDK 自带的全能分析工具,可以分析:内存快照、线程快照、程序死锁、监控内存的变化、 gc 变化等。

15.常用的JVM调优参数?
• -Xms2048M 最小内存2048M
• -Xmx2048M 最大内存2048M
• -XX:NewRatio=4 设置年轻的和老年代的内存比例为 1:4
• -XX:SurvivorRatio=8 设置新生代 Eden 和 Survivor 比例为 8:2
• -XX:+UseConcMarkSweepGC 指定使用 CMS + Serial Old 垃圾回收器组合;
• -XX:+PrintGC 开启打印 gc 信息;
• -XX:+PrintGCDetails 打印 gc 详细信息。

猜你喜欢

转载自www.cnblogs.com/lwx19960428/p/10709397.html
今日推荐