JVM面试题是Java面试经常考察的内容,下面给大家总结一份非常全面的JVM面试题及答案@mikechen
JVM是什么
JVM,全称是Java虚拟机,是Java编程语言的运行环境,它可以在不同的操作系统上运行Java程序。
Java虚拟机屏蔽了与具体操作系统平台相关的信息,使得Java程序只需生成在Java虚拟机上运行的目标代码字节码。
如下图所示:
简单来说JVM是用来解析和运行Java程序的,它是Java平台的核心组件,提供了许多功能,例如垃圾回收、内存管理、安全性和线程管理等。
JVM内存模型
JVM内存模型的整体结构,如下图所示:
包含:JVM堆、虚拟机栈、程序计数器、Java方法区、本地方法栈。
1.JVM堆(Heap)
它是Java虚拟机中最大的一块内存区域,用于存储对象实例和数组,堆是所有线程共享的,因此在多线程环境下需要注意并发访问的问题。
2.JVM方法区(Method Area)
它是所有线程共享的内存区域,用于存储已加载的类信息、常量、静态变量、即时编译器编译后的代码等。
方法区也称为永久代(PermGen),但在JDK8之后,永久代已被移除,被元空间(MetaSpace)所代替。
3.Java虚拟机栈(Java Virtual Machine Stacks)
用于存储方法的局部变量、操作数栈、动态链接、方法出口等信息。栈帧在方法执行结束后会被弹出。
4.程序计数器(Program Counter Register)
它是一块较小的内存区域,用于存储正在执行的Java虚拟机字节码指令的地址。
5.本地方法栈(Native Method Stacks)
它用于存储Java程序调用本地方法(Native Method)时的参数和返回值。
JVM垃圾回收算法
1.标记清除算法
如下图所示:
1.标记阶段
从程序的根对象开始,递归遍历所有可以到达的对象,并将它们标记为“可达”的对象。
2.清除阶段
遍历整个堆,将没有标记的对象,即未被标记为“可达”,视为垃圾并回收其占用的内存。
标记清除算法适用
标记清除算法适用于:存活对象较多的情况,比较适用于年老代。
2.复制算法
复制算法,如下图所示:
复制算法步骤,主要分为如下步骤:
第一步:标记出所有的存活对象
从根集合节点进行扫描,例如:线程栈中的对象、静态变量、寄存器中的指针等,标记出所有的存活对象,
第二步:复制对象到新内存
找出所有仍然存活的对象,并将这些存活的对象复制到一块儿新的内存,比如:上方图片下边的那一块儿绿色内存。
第三步:回收垃圾并被清除
当所有存活的对象都被复制到To区后,From区中的所有对象都可以被清除(图中上边的那一块儿内存)。
复制算法适合
复制算法适合存活对象较少的情况下比较高效,基本上98%的对象是”朝生夕死”的,存活下来的会很少,所以特别适合于新生代。
3.标记整理算法
如下图所示:
标记整理算法步骤,主要分为如下4个步骤:
- 遍历内存中的所有对象,标记出所有正在使用的对象。
- 将所有标记过的对象移动到内存的一端,形成一个连续的内存块,同时将这些对象的地址更新到新的位置上。
- 将内存块另一端的所有未标记对象删除,并将这些内存空间标记为可用。
- 更新所有指向移动对象的指针,使其指向新的地址。
标记整理算法适合
标记整理算法适合老年代进行垃圾收集,parallel Oldgc和Serial old收集器就是采用该算法进行回收的。
4.分代收集算法
分代收集算法就是目前虚拟机使用的回收算法,这种算法根据对象的存活周期的不同将内存划分成几块,新生代和老年代,这样就可以根据各个年代的特点采用最适当的收集算法。
JVM垃圾收集器
1.Serial串行收集器
Serial是一个新生代收集器,使用的是标记复制算法,Serial收集器是最基础也是历史最悠久的收集器。
如下图所示:
Serial串行收集器的主要特点是单线程收集,即只使用一个线程来完成垃圾收集工作,它使用标记复制算法进行垃圾回收。
2.Parallel并行收集器
Parallel并行收集器是在Serial收集器的基础上发展而来,如下图所示:
其主要特点是使用多个线程同时进行垃圾回收,从而提高垃圾回收的效率,它使用标记复制算法进行垃圾回收。
3.CMS收集器
CMS收集器,全称是Concurrent Mark Sweep,CMS收集器主要用于收集老年代的垃圾。
如下图所示:
相比于Serial和Parallel收集器,CMS收集器的主要特点是采用并发收集的方式,,采用的是标记清除算法。
4.G1收集器
G1垃圾收集器全称是Garbage First,G1垃圾收集器采用的是分代收集的思想。
如下图所示:
它将整个Java堆内存划分为多个大小相等的区域(Region),每个区域可以是年轻代,也可以是老年代。
G1收集器的阶段分以下几个步骤:
5.ZGC垃圾收集器
ZGC也称为The Z Garbage Collector,ZGC垃圾收集器是JDK 11中推出的一款追求极致低延迟的性质的JVM垃圾收集器。
与CMS中的ParNew和G1类似,ZGC也采用标记复制算法,不过ZGC对该算法做了重大改进。
6.Shenandoah垃圾收集器
Shenandoah垃圾收集器于JDK 12中首次引入,主要针对需要大内存和低延迟的应用场景。
JVM调优参数
以下是重要的JVM调优参数:
1.指定JVM的初始内存和最大内存
参数:
-Xms和-Xmx
示例:
-Xms512m -Xmx2g
指定JVM的初始内存为512MB,最大内存为2GB。
2.设置新生代的内存大小
参数:
-Xmn
示例:
-Xmn2g
Xmn2g:设置年轻代大小为2G。
3.指定持久代的初始大小和最大大小
参数:
-XX:PermSize和-XX:MaxPermSize
示例:
-XX:PermSize=128m -XX:MaxPermSize=256m
指定持久代的初始大小为128MB,最大大小为256MB。
4.启用G1垃圾收集器
参数:
-XX:+UseG1GC
示例:
java -XX:+UseG1GC Main
启用G1垃圾收集器。
5.启用CMS垃圾收集器
参数:
-XX:+UseConcMarkSweepGC
UseConcMarkSweepGC,表示启用CMS垃圾收集器。
6.打印垃圾收集器的详细信息和时间戳
参数:
-XX:+PrintGCDetails
参数:
-XX:+PrintGCDetails -XX:+PrintGCDateStamps
打印垃圾收集器的详细信息和时间戳。
7.调整新生代和老年代的比例
参数:
-XX:NewRatio=2
NewRatio=2表示新生代和老年代的比例为1:2。
8.调整Eden区和Survivor区的比例
参数:
-XX:SurvivorRatio=8
SurvivorRatio=8表示Eden区和Survivor区的比例为8:1。
JVM性能调优
JVM性能调优主要包含以下方法,大概分为5个步骤:
1.监控GC的状态
使用各种JVM调优工具,查看当前日志,分析当前JVM调优参数设置,并且分析当前堆内存快照和gc日志。
根据实际的各区域内存划分和GC执行时间,觉得是否进行优化。
举一个例子: 系统崩溃前的一些现象:
- 每次垃圾回收的时间越来越长;
- FullGC的次数越来越多;
- 逐渐到达OutOfMemoryError的临界值;
这个时候就需要分析JVM内存快照dump。
2.生成堆的dump文件
可以通过Java的jmap命令来生成该文件,需要分析dump文件。
3.分析dump文件
打开这个3G的堆信息文件,显然一般的Window系统没有这么大的内存,必须借助高配置的Linux,几种工具打开该文件:
- Visual VM;
- MAT;
- JDK 自带的Hprof工具等;
文件太大,建议使用Eclipse专门的静态内存分析工具Mat打开分析。
4.分析和调整
这里会涉及到如下内容:
- 调整垃圾回收机制,提高垃圾回收效率,避免长时间的停顿;
- 调整线程池大小,避免线程过多导致的性能下降;
- 优化代码,减少不必要的对象创建和内存占用等。
5.不断的试验和试错
最后,就需要通过不断的试验和试错,分析并找到最合适的参数,并则将这些参数应用到所有服务器。
以上就是JVM面试题及答案详解,更多JVM内容请查看:JVM(Java虚拟机)从0到1全部合集
陈睿mikechen
10年+大厂架构经验,资深技术专家,就职于阿里巴巴、淘宝、百度等一线互联网大厂。
关注「mikechen」公众号,获取更多技术干货!
后台回复【架构】,即可获取《阿里架构师进阶专题全部合集》,后台回复【面试】即可获取《史上最全阿里Java面试题总结》