Java面试题系列——JavaSE面试题(GC一)

1、说说你对Java的GC回收机制的理解

垃圾回收(Garbage Collection)是Java虚拟机(JVM)垃圾回收器提供的一种用于在空闲时间不定时回收无任何对象引用的对象占据的内存空间的一种机制。  (仅仅回收无引用对象所实际占用的空间,对象引用不回收)。

(1)对象回收的时机

1.引用计数法:引用计数算法是垃圾收集器中的早期策略。在对象中添加一个引用计数器,每当有一个地方 引用它时,计数器值就加一;当引用失效时,计数器值就减一;任何时刻计数器为零的对象就是不可 能再被使用的。引用计数算法(Reference Counting)虽然占用了一些额外的内存空间来进行计数,但 它的原理简单,判定效率也很高,在大多数情况下它都是一个不错的算法。

2.可达性分析算法:当前主流的商用程序语言(Java、C#,上溯至前面提到的古老的Lisp)的内存管理子系统,都是 通过可达性分析(Reachability Analysis)算法来判定对象是否存活的。这个算法的基本思路就是通过 一系列称为“GC Roots”的根对象作为起始节点集,从这些节点开始,根据引用关系向下搜索,搜索过 程所走过的路径称为“引用链”(Reference Chain),如果某个对象到GC Roots间没有任何引用链相连, 或者用图论的话来说就是从GC Roots到这个对象不可达时,则证明此对象是不可能再被使用的。

 其中,GC Roots包括以下几种:(a)虚拟机栈(栈帧中的局部变量表)中引用的对象;(b)方法区中类静态属性引用的对象;(c)方法区中常量引用的对象;(d)本地方法栈中Native方法引用的对象;

(2)垃圾回收算法

1.标记-清除算法:  算法分为“标记”“清除”两个阶段:首先标记出所有需要回 收的对象,在标记完成后,统一回收掉所有被标记的对象,也可以反过来,标记存活的对象,统一回 收所有未被标记的对象。标记过程就是对象是否属于垃圾的判定过程。

缺点:

a、执行效率不稳定。如果Java堆中包含大量对象,而且其中大部分是需要被回收的,这时必须进行大量标记和清除的动作,导致标记和清除两个过 程的执行效率都随对象数量增长而降低。
b、内存空间的碎片化问题。标记、清除之后会产生大量不连续的内存碎片,空间碎片太多可能会导致当以后在程序运行过程中需要分配较大对象时无法找 到足够的连续内存而不得不提前触发另一次垃圾收集动作。

2.标记-复制算法:  将可用 内存按容量划分为大小相等的两块,每次只使用其中的一块。当这一块的内存用完了,就将还存活着 的对象复制到另外一块上面,然后再把已使用过的内存空间一次清理掉。

3.标记-整理算法: 标记过程仍然与“标记-清除”算法一样,但后续步骤不是直接对可回收对象进行清理,而是让所有存活的对象都向内存空间一端移动,然后直接清理掉边界以外的内存。标记-清除算法与标记-整理算法的本质差异在于前者是一种非移动式的回收算法,而后者是移动式的。

(3)垃圾收集器

JVM中的垃圾收集器主要包括7种,即Serial,Serial Old,ParNew,Parallel Scavenge,Parallel Old以及CMS,G1收集器。如下图所示:

Java面试题系列——JavaSE面试题(GC一)_第1张图片

1、Serial收集器:

Serial收集器是一个单线程的垃圾收集器,并且在执行垃圾回收的时候需要 Stop The World。虚拟机运行在Client模式下的默认新生代收集器。Serial收集器的优点是简单高效,对于限定在单个CPU环境来说,Serial收集器没有多线程交互的开销。
 

2、Serial Old收集器:

Serial Old是Serial收集器的老年代版本,也是一个单线程收集器。主要也是给在Client模式下的虚拟机使用。在Server模式下存在主要是做为CMS垃圾收集器的后备预案,当CMS并发收集发生Concurrent Mode Failure时使用。
 

3、ParNew收集器:

ParNew是Serial收集器的多线程版本,新生代是并行的(多线程的),老年代是串行的(单线程的),新生代采用复制算法,老年代采用标记整理算法。可以使用参数:-XX:UseParNewGC使用该收集器,使用 -XX:ParallelGCThreads可以限制线程数量。
 

4、Parallel Scavenge垃圾收集器:

Parallel Scavenge是一种新生代收集器,使用复制算法的收集器,而且是并行的多线程收集器。Paralle收集器特点是更加关注吞吐量(吞吐量就是cpu用于运行用户代码的时间与cpu总消耗时间的比值)。可以通过-XX:MaxGCPauseMillis参数控制最大垃圾收集停顿时间;通过-XX:GCTimeRatio参数直接设置吞吐量大小;通过-XX:+UseAdaptiveSizePolicy参数可以打开GC自适应调节策略,该参数打开之后虚拟机会根据系统的运行情况收集性能监控信息,动态调整虚拟机参数以提供最合适的停顿时间或者最大的吞吐量。自适应调节策略是Parallel Scavenge收集器和ParNew的主要区别之一。
 

5、Parallel Old收集器:

Parallel Old是Parallel Scavenge收集器的老年代版本,使用多线程和标记-整理算法。

6、CMS(Concurrent Mark Sweep)收集器(并发标记清除)

CMS收集器是一种以获取最短回收停顿时间为目标的收集器。CMS收集器是基于标记-清除算法实现的,是一种老年代收集器,通常与ParNew一起使用。

CMS的垃圾收集过程分为4步:

  • 初始标记:需要“Stop the World”,初始标记仅仅只是标记一下GC Root能直接关联到的对象,速度很快。
  • 并发标记:是主要标记过程,这个标记过程是和用户线程并发执行的。
  • 重新标记:需要“Stop the World”,为了修正并发标记期间因用户程序继续运作而导致标记产生变动的那一部分对象的标记记录(停顿时间比初始标记长,但比并发标记短得多)。
  • 并发清除:和用户线程并发执行的,基于标记结果来清理对象。
     

Java面试题系列——JavaSE面试题(GC一)_第2张图片

CMS垃圾回收器的优缺点分析:

CMS以降低垃圾回收的停顿时间为目的,很显然其具有并发收集,停顿时间低的优点。

缺点主要包括如下:

  • 对CPU资源非常敏感,因为并发标记和并发清理阶段和用户线程一起运行,当CPU数变小时,性能容易出现问题。
  • 收集过程中会产生浮动垃圾,所以不可以在老年代内存不够用了才进行垃圾回收,必须提前进行垃圾收集。通过参数-XX:CMSInitiatingOccupancyFraction的值来控制内存使用百分比。如果该值设置的太高,那么在CMS运行期间预留的内存可能无法满足程序所需,会出现Concurrent Mode Failure失败,之后会临时使用Serial Old收集器做为老年代收集器,会产生更长时间的停顿。
  • 标记-清除方式会产生内存碎片,可以使用参数-XX:UseCMSCompactAtFullCollection来控制是否开启内存整理(无法并发,默认是开启的)。参数-XX:CMSFullGCsBeforeCompaction用于设置执行多少次不压缩的Full GC后进行一次带压缩的内存碎片整理(默认值是0)。

浮动垃圾:

由于在应用运行的同时进行垃圾回收,所以有些垃圾可能在垃圾回收进行完成时产生,这样就造成了“Floating Garbage”,这些垃圾需要在下次垃圾回收周期时才能回收掉。所以,并发收集器一般需要20%的预留空间用于这些浮动垃圾。

7、G1(Garbage-First)收集器:

G1收集器将新生代和老年代取消了,取而代之的是将堆划分为若干个区域,每个区域都可以根据需要扮演新生代的Eden和Survivor区或者老年代空间,仍然属于分代收集器,区域的一部分包含新生代,新生代采用复制算法,老年代采用标记-整理算法。

通过将JVM堆分为一个个的区域(region),G1收集器可以避免在Java堆中进行全区域的垃圾收集。G1跟踪各个region里面的垃圾堆积的价值大小(回收所获得的空间大小以及回收所需时间的经验值),在后台维护一个优先列表,每次根据回收时间来优先回收价值最大的region。
 

G1收集器的特点:

  • 并行与并发:G1能充分利用多CPU,多核环境下的硬件优势,来缩短Stop the World,是并发的收集器。
  • 分代收集:G1不需要其他收集器就能独立管理整个GC堆,能够采用不同的方式去处理新建对象、存活一段时间的对象和熬过多次GC的对象。
  • 空间整合:G1从整体来看是基于标记-整理算法,从局部(两个Region)上看基于复制算法实现,G1运作期间不会产生内存空间碎片。
  • 可预测的停顿:能够建立可以预测的停顿时间模型,预测停顿时间。
     

和CMS收集器类似,G1收集器的垃圾回收工作也分为了四个阶段:

  • 初始标记
  • 并发标记
  • 最终标记
  • 筛选回收

其中,筛选回收阶段首先对各个Region的回收价值和成本进行计算,根据用户期望的GC停顿时间来制定回收计划。

持续更新中,敬请期待!

参考文章:

浅析Java虚拟机的垃圾回收机制(GC)_only-code的博客-CSDN博客_java的gc回收机制

面试讲解JAVA GC(垃圾回收机制)_我有一头小花驴的博客-CSDN博客_java垃圾回收机制面试题 浅谈Java的GC回收机制的理解_Funky_oaNiu的博客-CSDN博客

深入理解Java垃圾回收机制-GC_毕加索丶的博客-CSDN博客

面试讲解JAVA GC(垃圾回收机制)_我有一头小花驴的博客-CSDN博客_java垃圾回收机制面试题

你可能感兴趣的:(JVM,java)