2021秋招最新JAVA面试题|垃圾收集器题目汇总

Posted BugGuys

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了2021秋招最新JAVA面试题|垃圾收集器题目汇总相关的知识,希望对你有一定的参考价值。

JAVA基础篇面试题

1. 简述四种垃圾回收器

串行垃圾回收器(serial)

概念:他为单线程环境设计且只使用一个线程进行垃圾回收,会暂停所有的用户线程,不适合服务器环境;

Serial收集器:单线程的新生代收集器,需要暂停其他线程。推荐在客户端模式下选用,由于没有线程交互的开销,可以获得最高的单线程收集效率。

并行垃圾回收器(Parallel)

概念:多个垃圾收集线程并行工作,此时用户线程是暂停的,适用于科学计算/大数据处理;

ParNew收集器:Serial收集器的多线程并发版本;

并发垃圾回收器(CMS)

概念:用户线程和垃圾收集线程同时执行(不一定是并行,可能交替执行),不需要停顿用户线程;

CMS收集器:以获得最短回收停顿时间为目的的收集器。基于标记-清除出算法;

G1垃圾回收器

将堆内存分割成不同的区域然后并发的对其进行垃圾回收;

一款主要面向服务端应用的垃圾收集器;使用Mixed GC模式,面向堆内存任何部分来组成回收集进行回收。标准就是哪块内存存放的垃圾数量最多,回收收益最大。整体看是标记整理算法实现,局部看,两个Region之间是标记复制算法实现。不会产生内存空间碎片。

G1把连续的JAVA堆内存划分为多个大小相等的独立区域(Region);每一个Region可以充当Eden,Survivor,老年代空间。还有Humongous区域,专门用来存储大对象。只要大小超过了一个Region的一半的对象即为大对象。

除G1外的图上其他收集器的特点:

  • 年轻代与老年代是各自独立且连续的内存块;
  • 年轻代垃圾收集是1个Eden+2个Survivor,使用复制算法;
  • 老年代收集必须扫描整个老年代区域;
  • 都是以尽可能少而快速地执行GC为设计原则;

2. 配置JVM的垃圾回收器

java的GC回收类型有:

UseSerialGC、UseParallelGC、UseConcMarkSweepGC、UseParNewGC、UseParallelOldGC、UseG1GC

# 查看JVM当前回收器
java -XX:PrintCommandLineFlags -version
# 默认的回收器是并行回收
-XX:+UseParallelGC
# 串行回收
-XX:+UseSerialGC
-----------------------------------------
-XX:+UseParNewGC #使用这个参数后会在新生代进行并行回收,老年代仍旧使用串行回收。新生代S区任然使用复制算法。操作系统是多核CPU上效果明显,单核CPU建议使用串行回收器。打印GC详情时ParNew标识着使用了ParNewGC回收器。默认关闭。
-XX:+UseConcMarkSweepGC #并发标记清除,即使用CMS收集器。它是和应用程序线程一起执行,相对于Stop The World来说虚拟机停顿时间较少。停顿减少,吞吐量会降低。它使用的是 标记清除算法,运作过程为四个步骤,分别是 初始标记—并发标识—重新标记—并发清除。它是老年代的收集算法,新生代使用ParNew收集算法。默认关闭
-XX:+UseCMSCompactAtFullCollection # Full GC后,进行一次整理,整理过程是独占的,会引起停顿时间变长。仅在使用CMS收集器时生效。
-XX:CMSFullGCsBeforeCompaction=0 #设置在执行多少次Full GC后对内存空间进行压缩整理。

3. 垃圾收集器对应收集区域

4. JVM的Client和Server模式是什么

32位的WindowsOS,无论硬件如何都默认使用Client的JVM模式;

32位的其他OS,2G内存同有2个cpu以上用Server模式,低于则默认使用Client模式;

64位OS都是server模式;

5. 垃圾收集器的详细总结

Serial收集器

作用范围:新生代

概念: 单线程的新生代收集器,需要暂停其他线程。推荐在客户端模式下选用,由于没有线程交互的开销,可以获得最高的单线程收集效率。

工作流程:

优势:古老、简单、稳定、高效;

​ 单核下Client模式的默认新生代垃圾收集器;

不足:需要暂停用户线程,停顿时间长;

​ 仅有一个线程去回收;

配置:-XX:+UseSerialGC

配置后会默认使用:Serial(新生代)+Serial Old(老年代)的组合;

ParNew收集器

作用范围:新生代

概念:使用多线程进行垃圾回收,是Serial收集器的多线程并行版本;会有Stop-The-World情况,常见的应用场景是配合老年代的CMS GC工作,其余和Serial收集器一样;

工作流程:

优势:多线程、稳定、高效;

​ 很多Server模式的默认新生代垃圾收集器;

不足:需要暂停用户线程;

配置:-XX:+UseParNewGC配置后只影响新生代,不影响老年代;

-XX:ParallelGCThreads设置回收线程数量,默认开启和CPU数目相同的线程数;

配置后默认开启:ParNew(新生代)+Serial Old(老年代)的组合;但JDK8后不推荐此使用并且JDK9后不再支持该默认组合;

Parallel Scavenge收集器

作用范围:新生代

概念:类似于ParNew收集器,使用复制算法,并行的多线程垃圾收集器,俗称吞吐量优先收集器。就是说,串行收集器在新生代和老年代并行化;

工作流程:

优势:1. 可控制吞吐量,根据公式,程序运行100min,垃圾收集时间1min,吞吐量就是99%;高吞吐量意味着高效利用CPU的时间,它多用于在后台运算不需要太多交互的任务;
吞 吐 量 = 运 行 用 户 代 码 时 间 运 行 用 户 代 码 时 间 + 运 行 垃 圾 收 集 时 间 吞吐量=\\frac{运行用户代码时间}{运行用户代码时间+运行垃圾收集时间} =+
​ 2.自适应调节策略,虚拟机根据当前系统的运行情况手机性能监控信息,动态调整这些参数以提供最合适的停顿时间(-XX:MaxGCPauseMillis)或最大吞吐量;

配置:-XX:+UseParallelGC-XX:+UseParallelOldGC可互相激活,使用该收集器;

-XX:ParallelGCThreads=N设置回收线程数量;

​ 当 CPU 数量小于8, ParallelGCThreads 的值等于 CPU 数量,当 CPU 数量大于 8 时,则使用公式GC实际线程数N=8 + ((CPU - 8) * 5/8) = 3 +((5*CPU)/ 8)

​ 由于GC操作会暂停所有的应用程序线程,JVM为了尽量缩短停顿时间就必须尽可能地利用更多的CPU资源。这意味着,默认情况下,JVM会在机器的每个CPU上运行一个线程,最多同时运行8个。一旦达到这个上限,JVM会调整算法,每超出5/8个CPU启动一个新的线程。所以总的线程数就是(这里的N代表CPU的数目):ParallelGCThreads = 8 + ((CPU - 8) * 5/8) 此处链接

配置第一个自动激活老年代ParallelOld收集器,或者配置ParallelOld老年代收集器,自动激活新生代Parallel收集器;

配置后:新生代使用Parallel Scavenge收集器,老年代使用ParallelOld收集器;

Parallel Old收集器

作用范围:老年代

概念:是Parallel Scavenge的老年代版本,使用多线程的标记-整理算法;

优势:提供了吞吐量优先的垃圾收集器

工作流程:

配置:-XX:+UseParallelOldGC

配置后:新生代使用Parallel + 老年代Parallel Old

CMS收集器

作用范围:老年代

概念:Concurrent Mark Sweep,并发标记清除;是一种以获取最短回收停顿时间为目标的收集器;适用于在互联网站或者B/S系统的服务器上,这类应用尤其重视服务器的响应速度,希望系统停顿时间最短。CMS非常适合堆内存大,CPU核数多的服务器端应用,也是G1出现之前大型应用的首选收集器;

工作流程:

  • 初始标记:标记一下GC Roots能直接关联的对象,速度很快。需要停顿用户线程
  • 并发标记:从根开始遍历整个对象图的过程,过程耗时长,但不需要停顿用户线程。
  • 重新标记:为了修正用户线程继续运作而导致标记变动部分对象的标记记录,这一阶段会比初始阶段稍长,但比并发标记时间短。需要停顿用户线程
  • 并发清除:清理掉已死亡的对象,不需要移动存活对象,可以与用户线程同时并发。

优势:并发收集停顿低,并发是指与用户线程一起执行;

不足:1.对处理器资源非常敏感。会占用一部分线程降低总吞吐量。默认启动的回收线程数是 (处理器核心数+3)/4;

​ 2.无法处理浮动垃圾。在并发标记和并发清理过程中,会产生新的垃圾对象,CMS无法在当次收集中处理掉他们,只好在下一次清理。这部分垃圾称为浮动垃圾。

​ 3.CMS使用标记清除算法,会产生大量的碎片化空间。最后需要通过担保机制对堆内存进行压缩。CMS提供了参数-XX:CMSFullGCsBeforeCompaction(默认0,即每次都进行内存整理)来指定多少次CMS收集之后,进行一次压缩的Full GC;

配置:-XX:+UseConcMarkSweepGC

配置该参数后会自动打开配置-XX:+UseParNewGC

该参数开启后使用的是:ParNew新生代 + CMS老年代 + Serial Old的收集器组合,Serial Old将作为CMS出错的后备收集器;

Serial Old收集器

作用范围:老年代

概念:是Serial的老年代版本,同样是单线程收集器,使用标记-整理算法,这个收集器也主要是运行在Client默认的java虚拟机默认的老年代垃圾收集器;也是CMS的兜底收集器;

工作流程:

配置:-XX:+UseSerialOldGCJDK8以后配置无效,已被取消;虚拟机会无法启动,显示该配置无效;

G1收集器

作用范围:整个堆

概念:将堆内存分割成不同的区域然后并发的对其进行垃圾回收;

一款主要面向服务端应用的垃圾收集器;使用Mixed GC模式,面向堆内存任何部分来组成回收集进行回收。标准就是哪块内存存放的垃圾数量最多,回收收益最大。整体看是标记整理算法实现,局部看,两个Region之间是标记复制算法实现。不会产生内存空间碎片。

G1把连续的JAVA堆内存划分为多个大小相等的独立区域(Region);每一个Region可以充当Eden,Survivor,老年代空间。还有Humongous区域,专门用来存储大对象。只要大小超过了一个Region的一半的对象即为大对象。

内存空间:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-6qfjATAk-1631581055744)(./imgs/G1收集器内存图.jpg)]

针对Eden区进行收集,Eden区耗尽后会触发垃圾收集,主要是小区域收集+形成连续的内存块,避免内存碎片;

Eden区的数据移动到Survivor区,假如出现Survivor区空间不够,Eden区数据会部分晋升到Old区;

Survivor区的数据移动到新的Survivor区,部分数据晋升到Old区;

最后Eden区收集干净,GC结束,用户线程继续执行;

工作流程:

  • 初始标记:标记GC Roots能直接关联的对象,并修改TAMS的指针,需要停顿线程,耗时短,借助Minor GC时同步完成。实际没有额外停顿。
  • 并发标记:从根开始进行可达性分析,耗时长但可并行,完成后重新处理原始快照下有变动的对象。
  • 最终标记:对用户线程做另一个短暂的暂停,用于处理并发阶段结束后仍遗留下的少量SATB(原始快照)记录。
  • 筛选回收:统计数据,按回收价值和成本排序,将存活对象复制到空Region并清理旧的Region空间,暂停用户线程,并行完成清理和移动对象。

优势:高吞吐量,尽可能满足垃圾收集暂停时间的要求;

​ 像CMS收集器一样,能与应用程序并发执行;

​ 整理空闲空间更快,没有内存碎片;

​ 可预测GC停顿时间,用户可以指定期望停顿的时间;

​ 保证高吞吐性能和不需要更大的堆空间;

G1相比CMS的不足:

  1. G1在垃圾收集产生的内存占用与程序运行额外执行负载都比CMS高;
  2. G1卡表实现复杂,每个Region均有一个,消耗内存大,CMS只有一个,实现简单,只需要处理老年代到新生代的引用,节省空间。
  3. 负载角度:CMS使用写后屏障更新维护卡表,G1还需要使用写前卡表跟踪并发时指针变化。G1需实现类似小消息队列的结构,将写前,写后屏障放到队列异步处理。

配置:-XX:+UseG1GC

-XX:G1HeapRegionSize=n指定每个Region分区的大小(1MB~32MB,是2的幂),默认将整堆划分为2048个分区;

-XX:MaxGCPauseMillis=n最大GC停顿时间,JVM尽可能但不保证停顿小于这个时间(毫秒),可以设置为100;

-XX:InitiatingHeapOccupancyPercent=n堆占用了多少的时候就触发GC,默认45;

-XX:ConcGCThreads=n并发GC使用的线程数;

-XX:G1ReservePercent=n设置作为空闲空间的预留内存百分比,以降低目标空间溢出的风险,默认值是10%;

6. 如何选择垃圾收集器

  • 单CPU或小内存,单机程序

    -XX:+UseSerialGC

  • 多CPU,需要最大吞吐量,如后台计算型应用

    -XX:+UseParallelGC 或者 -XX:+UseParallrelOldGC

  • 多CPU,追求低停顿,需要快速响应如互联网应用

    -XX:+UseConcMarkSweepGC

    -XX:+ParNewGC

7. github奇淫技巧

xxx关键词 in:name,description,readme 表示关键字在这其中的;

xxx关键词 stars:>=5000 表示点赞数大于等于五千;

xxx关键词 forks:>=5000 表示forks大于等于五千;

xxx关键词 forks:100…200 stars:80…100 表示关键词forks在100到200内,stars在80到100内;

awesome xxx关键词 表示awesome系列,用来收集学习,工具,书籍类相关的项目;

location:地区,language:语言

location:hangzhou language:java 表示搜索杭州java大佬

给别人的代码行高亮(单行):git地址#L行号

https://github.com/NervJS/taro/blob/next/package.json#L8

给别人的代码行高亮(多行):git地址#L行号-L行号

https://github.com/wuba/Taro-Mortgage-Calculator/blob/master/package.json#L2-L10

github下将项目列表收缩快速显示 按键盘t键:

其余快捷键

以上是关于2021秋招最新JAVA面试题|垃圾收集器题目汇总的主要内容,如果未能解决你的问题,请参考以下文章

2021最新中高级Java面试题目,Java面试题汇总

Java技术类校招面试题汇总:2021最新Java笔试题目

2021秋招最新JAVA面试题|JVM剖析与常用的调优总结

2021最新Java笔试题目,透彻分析源码

分享互联网2021年最新Java面试题汇总整理-附详细答案解析

自动驾驶面试题汇总(2022秋招题库)—— 持续更新