JAVA基础篇面试题
文章目录
- JAVA基础篇面试题
- 1. 简述四种垃圾回收器
- 串行垃圾回收器(serial)
- 并行垃圾回收器(Parallel)
- 并发垃圾回收器(CMS)
- G1垃圾回收器
- 2. 配置JVM的垃圾回收器
- 3. 垃圾收集器对应收集区域
- 4. JVM的Client和Server模式是什么
- 5. 垃圾收集器的详细总结
- Serial收集器
- ParNew收集器
- Parallel Scavenge收集器
- Parallel Old收集器
- CMS收集器
- Serial Old收集器
- G1收集器
- 6. 如何选择垃圾收集器
- 7. github奇淫技巧
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:+UseSerialOldGC
JDK8以后配置无效,已被取消;虚拟机会无法启动,显示该配置无效;
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的不足:
- G1在垃圾收集产生的内存占用与程序运行额外执行负载都比CMS高;
- G1卡表实现复杂,每个Region均有一个,消耗内存大,CMS只有一个,实现简单,只需要处理老年代到新生代的引用,节省空间。
- 负载角度: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
键:
其余快捷键