面试题首页 > JVM面试题

JVM垃圾回收机制面试题

001什么是GC机制?

Java GC(Garbage Collection)垃圾回收机制,是Java与C++/C的主要区别。JVM通过GC来回收堆和方法区中的内存,这个过程是自动执行的。因此作为Java开发者,不需要专门去编写内存回收和垃圾清理代码,也不需要处理内存泄露和溢出的问题。虽然java不需要开发人员显示的分配和回收内存,这对开发人员确实降低了不少编程难度,但也可能带来一些副作用:
1.有可能不知不觉浪费了很多内存;
2.JVM花费过多时间来进行内存回收;
3.内存泄露;
Java GC机制主要完成3件事:确定哪些内存需要回收;确定什么时候需要执行GC;如何执行GC。

002如和判断一个对象是否存活?

1.引用计数法
所谓引用计数法就是给每一个对象设置一个引用计数器,每当有一个地方引用这个对象时,就将计数器加一,引用失效时,计数器就减一。当一个对象的引用计数器为零时,说明此对象没有被引用,也就是“死对象”,将会被垃圾回收.
引用计数法有一个缺陷就是无法解决循环引用问题,也就是说当对象 A 引用对象 B,对象B 又引用者对象 A,那么此时 A,B 对象的引用计数器都不为零,也就造成无法完成垃圾回收,所以主流的虚拟机都没有采用这种算法。
2.可达性算法(引用链法)
该算法的思想是:从一个被称为 GC Roots的对象开始向下搜索,如果一个对象到 GCRoots 没有任何引用链相连时,则说明此对象不可用。
在 java 中可以作为 GC Roots 的对象有以下几种:
(1)虚拟机栈中引用的对象方法区类静态属性引用的对象方法区常量池引用的对象本地方法栈 JNI 引用的对象
虽然这些算法可以判定一个对象是否能被回收,但是当满足上述条件时,一个对象比不一定会被回收。当一个对象不可达 GC Root 时,这个对象并不会立马被回收,而是出于一个死缓的阶段,若要被真正的回收需要经历两次标记
(2)如果对象在可达性分析中没有与 GC Root 的引用链,那么此时就会被第一次标记并且进行一次筛选,筛选的条件是是否有必要执行 finalize()方法。当对象没有覆盖 finalize()方法或者已被虚拟机调用过,那么就认为是没必要的。
(3)如果该对象有必要执行 finalize()方法,那么这个对象将会放在一个称为 F-Queue 的对队列中,虚拟机会触发一个 Finalize()线程去执行,此线程是低优先级的,并且虚拟机不会承诺一直等待它运行完,这是因为如果 finalize()执行缓慢或者发生了死锁,那么就会造成 FQueue 队列一直等待,造成了内存回收系统的崩溃。GC 对处于 F-Queue 中的对象进行第二次被标记,这时,该对象将被移除”即将回收”集合,等待回收。

003垃圾回收方式?

GC按照回收区域又分为两大种类型:部分收集和整堆收集。
部分收集(Partial GC):不是完整收集整个Java堆的垃圾收集。其中又分为:
1. 新生代收集(Minor GC/Young GC):只是新生代的垃圾收集
当年轻代空间不足时,就会触发MinorGC,这里的年轻代满指的是Eden代满,Survivor满不会引发GC。
2. 老年代收集(MajorGC/o1dGC):只是老年代的圾收集。
3. 混合收集(MixedGC):收集整个新生代以及部分老年代的垃圾收集。
整堆收集(FullGC):收集整个java堆和方法区的垃圾收集。

004描述下GC过程。

1.在初始阶段,新创建的对象被分配到Eden区,S0和S1的两块空间都为空。
2.当Eden区满了的时候,Minor GC 被触发 。经过扫描与标记,不存活的对象被回收,存活的对象被复制到S0,并且存活的对象年龄都增大一岁。
3.当Eden区又满的时候,Minor GC再次被触发。此时Eden区 和 S0区存活的对象要复制到S1。需要注意的是,此时Eden区和S0区被清空,S0中的对象复制到S1后其年龄要加1。
4.当Eden区再次又满的时候,MinorGC则重复上面过程,将Eden区 和 S1区存活的对象复制到S0。此时Eden区和S1区被清空,S0中的对象复制到S1后其年龄要加1。
5.经过几次Minor GC之后,当存活对象的年龄达到一个阈值之后(-XX:MaxTenuringThreshold默认是15),就会被从年轻代Promotion到老年代。
6.新生代 GC(Minor GC):指发生新生代的的垃圾收集动作,Minor GC 非常频繁,回收速度一般也比较快。
7.老年代 GC(Major GC/Full GC):指发生在老年代的 GC,出现了 Major GC 经常会伴随至少一次的 Minor GC(并非绝对),Major GC 的速度一般会比 Minor GC 的慢 10 倍以上。

005解释强、软、弱、虚引用?

JDK1.2 以前,一个对象只有被引用和没有被引用两种状态。后来,Java 对引用的概念进行了扩充,将引用分为强引用(Strong Reference)、软引用(Soft Reference)、弱引用(Weak Reference)、虚引用(Phantom Reference)4 种,这 4 种引用强度依次逐渐减弱。

006垃圾回收算法有哪些?

一共有 4 种:标记-清除算法、复制算法、标记整理算法、分代收集算法;

007什么是标记-清除算法?

最基础的收集算法是“标记-清除”(Mark-Sweep)算法,分为“标记”和“清除”两个阶段:首先标记出所有需要回收的对象,在标记完成后统一回收所有被标记的对象。

008标记-清除算法的缺点?

● 效率问题,标记和清除两个过程的效率都不高;
● 空间问题,标记清除之后会产生大量不连续的内存碎片,空间碎片太多可能会导致以后在程序运行过程中需要分配较大对象时,无法找到足够的连续内存而不得不提前触发另一次垃圾收集动作。

009什么是复制算法?

它将可用内存按容量划分为大小相等的两块,每次只使用其中的一块。当这一块的内存用完了,就将还存活着的对象复制到另外一块上面,然后再把已使用过的内存空间一次清理掉。这样使得每次都是对整个半区进行内存回收,内存分配时也就不用考虑内存碎片等复杂情况,只要移动堆顶指针,按顺序分配内存即可,实现简单,运行高效。只是这种算法的代价是将内存缩小为了原来的一半。复制算法的执行过程如下图:

一般虚拟机都采用这种算法来回收新生代,因为新生代中的对象 98% 是“朝生夕死”的,所以并不需要按照 1:1 的比例来划分内存空间,而是将内存分为一块较大的 Eden 空间和两块较小的 Survivor 空间,每次使用 Eden 和其中一块 Survivor 。当回收时,将 Eden 和 Survivor 中还存活着的对象一次性地复制到另外一块 Survivor 空间上,最后清理掉 Eden 和刚才用过的 Survivor 空间。HotSpot 虚拟机默认 Eden:Survivor = 8:1,也就是每次新生代中可用内存空间为整个新生代容量的 90%(其中一块Survivor不可用),只有 10% 的内存会被“浪费”。当然如果另外一块 Survivor 空间没有足够空间存放上一次新生代收集下来的存活对象时,这些对象将直接通过分配担保机制进入老年代。

010复制算法缺点?

复制算法适合年轻代,不适合老年代。因为在对象存活率较高时就要进行较多的复制操作,效率将会变低。更关键的是复制算法需要有额外的空间进行分配担保,以应对被使用的内存中所有对象都 100% 存活的极端情况。

011什么是标记-整理算法

根据老年代的特点,有人提出了另外一种“标记-整理”(Mark-Compact)算法,标记过程仍然与“标记-清除”算法一样,但后续步骤不是直接对可回收对象进行清理,而是让所有存活的对象都向一端移动,然后直接清理掉端边界以外的内存。

012什么是分代收集算法?

"分代收集"(Generational Collection)算法是根据对象存活周期的不同将内存划分为几块并采用不同的垃圾收集算法。一般是把 Java 堆分为新生代和老年代,这样就可以根据各个年代的特点采用最适当的收集算法。在新生代中,每次垃圾收集时都发现有大批对象死去,只有少量存活,那就选用复制算法,只需要付出少量存活对象的复制成本就可以完成收集。而老年代中因为对象存活率高、没有额外空间对它进行分配担保,就必须使用“标记—清理”或者“标记—整理”算法来进行回收。

013Stop The World是什么意思?

进行垃圾收集时,必须暂停其他所有工作线程,Sun将这种事情叫做"Stop The World"。

014什么情况下新生代对象会晋升到老年代?

如果新生代的垃圾收集器为Serial和ParNew,并且设置了-XX:PretenureSizeThreshold参数,当对象大于这个参数值时,会被认为是大对象,直接进入老年代。
Young GC后,如果对象太大无法进入Survivor区,则会通过分配担保机制进入老年代。
对象每在Survivor区中“熬过”一次Young GC,年龄就增加1岁,当它的年龄增加到一定程度(默认为15岁,可以通过-XX:MaxTenuringThreshold设置),就将会被晋升到老年代中。
如果在Survivor区中相同年龄所有对象大小的总和大于Survivor空间的一半,年龄大于或等于该年龄的对象就可以直接进入老年代,无须等到MaxTenuringThreshold中要求的年龄。

015新生代中Eden区和Survivor区的默认比例?

在HotSpot虚拟机中,Eden区和Survivor区的默认比例为8:1:1,即-XX:SurvivorRatio=8,其中Survivor分为From Survivor和ToSurvivor,因此Eden此时占新生代空间的80%。

016Minor GC ,Major GC,Full GC是什么?

Minor GC是当年轻代空间不足时,就会触发MinorGC,这里的年轻代满指的是Eden代满,Survivor满不会引发GC(每次Minor GC会清理年轻代的内存)。因为Java对象大多都具备朝生夕灭的特性,所以Minor GC非常频繁,一般回收速度也比较快。这一定义既清晰又易于理解。Minor GC会引发STW,暂停其它用户的线程,等垃圾回收结束,用户线程才恢复运行
Major GC指发生在老年代的GC,对象从老年代消失时,我们说"Major Gc"或"Full GC"发生了。出现了MajorGc,经常会伴随至少一次的Minor GC(但非绝对的,在Paralle1 Scavenge收集器的收集策略里就有直接进行MajorGC的策略选择过程),也就是在老年代空间不足时,会先尝试触发MinorGc。如果之后空间还不足,则触发Major GC,Major GC的速度一般会比MinorGc慢1e倍以上,STW的时间更长,如果Major GC后,内存还不足,就报OOM了;
Full GC是对年轻代和老年代都进行垃圾回收,Full GC 是开发或调优中尽量要避免的,这样暂时时间会短一些。

017Minor GC和Full GC的触发条件?

Minor GC触发条件: 当Eden区满时,触发Minor GC。
Full GC触发条件:
(1)调用System.gc时,系统建议执行Full GC,但是不必然执行
(2)老年代空间不足
(3)方法区空间不足
(4)通过Minor GC后进入老年代的平均大小大于老年代的可用内存
(5)由Eden区、From Space区向To Sp3ace区复制时,对象大小大于To Space可存,则把该对象转存到老年代,且老年代的可用内存小于该对象大小;

018垃圾收集器有哪些?

019Serial垃圾收集器?

最基本的垃圾收集器,使用复制算法,单线程,虽然收集垃圾时需要暂停其他所有的工作线程,但简单高效,是 java 虚拟机运行在 Client 模式下默认的新生代垃圾收集器。
在HotSpot虚拟机中,使用-XX:+UseSerialGC参数可以指定年轻代和老年代都使用串行收集器。等价于新生代用Serial GC,且老年代用Serial Old GC。

020ParNew 垃圾收集器?

是 Serial 收集器的多线程版本 ,除了多线程进行GC外,其他与Serial一样,默认开启和 CPU 数目相同的线程数 。是很多 java虚拟机运行在 Server 模式下新生代的默认垃圾收集器。
1)可以通过选项"-XX:+UseParNewGC"手动指定使用ParNew收集器执行内存回收任务。它表示年轻代使用并行收集器,不影响老年代
2)这里的多线程指的是垃圾收集时,多线程并行,并不是垃圾收集与程序运行并行
3)收集垃圾时,也需要暂停其他所有工作线程,然后多线程收集垃圾。
4)单CPU环境下,因为线程切换,性能较差。

021Parallel Scavenge 收集器?

关注程序的吞吐量,即吞吐量优先。主要适用于在后台运算而不需要太多交互的任务。 自适应调节策略也是 ParallelScavenge 收集器与 ParNew 收集器的一个重要区别。
1)吞吐量=运行用户代码时间/(运行用户代码时间+垃圾收集时间) ; 吞吐量优先,意味着在单位时间内,STW的时间最短;与之相对应的 低延迟 就是暂停时间优先,尽可能让单次STW时间最短;这两个无法同时实现。
2)收集垃圾时,也需要暂停其他所有工作线程,然后多线程收集垃圾。
3)参数配置
-XX:+UseParallelGC 手动指定年轻代使用Parallel并行收集器执行内存回收任务。 
-XX:+UseParallelOldGC 手动指定老年代都是使用并行回收收集器。 
-XX:ParallelGCThreads 设置年轻代并行收集器的线程数。一般地,最好与CPU数量相等,以避免过多的线程数影响垃圾收集性能。  
-XX:MaxGCPauseMillis 设置垃圾收集器最大停顿时间(即STw的时间),单位是毫秒。 为了尽可能地把停顿时间控制在MaxGCPauseMills以内,收集器在工作时会调整Java堆大小或者其他一些参数。对于用户来讲,停顿时间越短体验越好。但是在服务器端,我们注重高并发,整体的吞吐量。所以服务器端适合Parallel进行控制。该参数使用需谨慎。 
-XX:GCTimeRatio 垃圾收集时间占总时间的比例(=1/(N+1))。用于衡量吞吐量的大小。 取值范围(0, 100)。默认值99,也就是垃圾回收时间不超过1%。与前一个-XX:MaxGCPauseMillis参数有一定矛盾性。暂停时间越长,Radio参数就容易超过设定的比例。  
-XX:+UseAdaptivesizePolicy 设置Parallel Scavenge收集器具有自适应调节策略 。在这种模式下,年轻代的大小、Eden和Survivor的比例、晋升老年代的对象年龄等参数会被自动调整,已达到在堆大小、吞吐量和停顿时间之间的平衡点。在手动调优比较困难的场合,可以直接使用这种自适应的方式,仅指定虚拟机的最大堆、目标的吞吐量(GCTimeRatio)和停顿时间(MaxGCPauseMills,让虚拟机自己完成调优工作。

022Serial Old?

1)是Serial的老年代版本,收集垃圾时也需要暂停其他所有的工作线程。
2)是Client模式下默认的老年代垃圾收集器
3)Server模式下,搭配新生代的Parallel Scavenge 收集器使用(在 JDK1.5 之前版本中)。同时也作为老年代中使用 CMS 收集器的后备垃圾收集方案(当CMS发生Concurrent Mode Failure)。

023Parallel Old收集器?

1)Parallel Scavenge的老年代版本
2)吞吐量优先,意味着在单位时间内,STW的时间最短;与之相对应的 低延迟 就是暂停时间优先,尽可能让单次STW时间最短;这两个无法同时实现。
3)若相同对于吞吐量要求较高,可以Parallel Scavenge搭配Parallel Old使用。

024介绍CMS垃圾收集器的特点?

CMS(Concurrent Mark Sweep)收集器是一种以获取最短回收停顿时间为目标的收集器。目前很大一部分的Java应用集中在互联网站或者B/S系统的服务端上,这类应用尤其重视服务的响应速度,希望系统停顿时间最短,以给用户带来较好的体验。CMS收集器就非常符合这类应用的需求。
从名字(包含“Mark Sweep”)上就可以看出,CMS收集器是基于“标记—清除”算法实现的,它的运作过程可以分为6个步骤,包括:初始标记、并发标记、预处理、重新标记、并发清除、重置。
CMS是一款优秀的收集器,它的主要优点在名字上已经体现出来了:并发收集、低停顿,但是CMS还远达不到完美的程度,它有以下3个明显的缺点:
(1)CMS收集器对CPU资源非常敏感。
(2)CMS收集器无法处理浮动垃圾(Floating Garbage),可能出现“Concurrent Mode Failure”失败而导致另一次Full GC的产生。
(3)CMS是一款基于“标记—清除”算法实现的收集器,这意味着收集结束时会有大量空间碎片产生。

025介绍下G1垃圾收集器的特点?

G1(Garbage-First)收集器是当今收集器技术发展的最前沿成果之一。G1是一款面向服务端应用的垃圾收集器。与其他GC收集器相比,G1具备如下特点:并行与并发、分代收集、空间整合、可预测的停顿。
在G1之前的其他收集器进行收集的范围都是整个新生代或者老年代,而G1不再是这样。使用G1收集器时,Java堆的内存布局就与其他收集器有很大差别,它将整个Java堆划分为多个大小相等的独立区域,虽然还保留有新生代和老年代的概念,但新生代和老年代不再是物理隔离的了,它们都是一部分Region(不需要连续)的集合。
G1收集器之所以能建立可预测的停顿时间模型,是因为它可以有计划地避免在整个Java堆中进行全区域的垃圾收集。G1跟踪各个Region里面的垃圾堆积的价值大小(回收所获得的空间大小以及回收所需时间的经验值),在后台维护一个优先列表,每次根据允许的收集时间,优先回收价值最大的Region(这也就是Garbage-First名称的来由)。这种使用Region划分内存空间以及有优先级的区域回收方式,保证了G1收集器在有限的时间内可以获取尽可能高的收集效率。
Mixed GC是G1垃圾收集器特有的收集方式,Mixed GC大致可划分为全局并发标记(global concurrent marking)和拷贝存活对象(evacuation)两个大部分:
global concurrent marking是基于SATB形式的并发标记,包括以下4个阶段:初始标记(Initial Marking)、并发标记(Concurrent Marking)、最终标记(Final Marking)、清理(Clean Up)。Evacuation阶段是全暂停的。它负责把一部分region里的活对象拷贝到空region里去,然后回收原本的region的空间。

026垃圾收集器的比较图。

垃圾收集器 分类 作用位置 使用算法 特点 适用场景
Serial 串行 新生代 复制算法 响应速度优先 适用于单CPU环境下的client模式
ParNew 并行 新生代 复制算法 响应速度优先 多CPU环境Server模式下与CMS配合使用
Parallel 并行 新生代 复制算法 吞吐量优先 适用于后台运算而不需要太多交互的场景
Serial Old 串行 老年代 标记-整理(压缩)算法 响应速度优先 适用于单CPU环境下的Client模式
Paraller Old  并行 老年代 标记-整理(压缩)算法 标记-整理(压缩)算法 适用于后台运算而不需要太多交互的场景
CMS 并发 老年代 标记-清除算法 响应速度优先 适用于互联网或B/S业务
G1 并发、并行 新生代、老年代 标记-整理(压缩)算法 响应速度优先 响应速度优先

目录

返回顶部