面试官问我--JVM 七种垃圾收集器解析

垃圾检测和收集算法只是内存回收的方法论,而垃圾收集器才是内存回收的具体实现(可理解为“接口”与“实现类”的关系)。
ps:GC垃圾回收(垃圾检测-回收算法):https://editor.csdn.net/md/?articleId=103819619

垃圾收集器分类:

在这里插入图片描述
新生代的收集器包括

  • Serial
  • PraNew
  • Parallel Scavenge

老年代的收集器包括

  • Serial Old
  • Parallel Old
  • CMS

回收整个Java堆(新生代和老年代)

  • G1收集器

新生代垃圾收集器解析

Serial 收集器
Serial 收集器是最基础、历史最悠久的收集器。特点:

  • 单线程收集,且垃圾收集时,必须暂停其他所有的工作线程(Stop The World, STW),直到它收集结束。
  • HotSpot 虚拟机运行在 Client 模式下默认新生代收集器。
  • 优于其他收集器的地方:简单而高效(与其他收集器的单线程比)。对于限定单个 CPU 的环境来说,Serial
    收集器由于没有线程交互的开销,专心做垃圾收集自然可以获得最高的单线程收集效率。

运行示意图如下:
在这里插入图片描述
ParNew 收集器
ParNew 收集器实质上是 Serial 收集器的多线程并行版本。
除了同时使用多条线程进行垃圾收集之外,其余的行为包括 Serial 收集器可用的所有控制参数(-XX:SurvivorRatio, -XX:PretenureSizeThreshold、-XX:HandlePromotionFailure 等)、收集算法、Stop The World、对象分配原则、回收策略等都与 Serial 收集器完全一致。
运行示意图:
在这里插入图片描述
使用/禁用该收集器的 VM 参数
注:JDK 9 取消了 -XX:+UseParNewGC 参数

-XX:+/-UseParNewGC

Parallel Scavenge 收集器
Parallel Scavenge 收集器是新生代收集器,也是使用标记-复制算法实现的、并行收集的多线程收集器,也称“吞吐量优先收集器”。
与 ParNew 类似,但关注点不同:

  • CMS 等收集器:尽可能地缩短垃圾收集时用户线程的停顿时间;
  • Parallel Scavenge 收集器:达到一个可控的吞吐量(Throughput)。

吞吐量 = 运行用户代码时间 / (运行用户代码时间 + 垃圾收集时间),即运行用户代码时间所占比重。
响应速度快能提升用户体验;而吞吐量高则能更高效地利用 CPU 资源,尽快完成程序的计算任务(主要适合在后台运算而不需要太多交互的任务)。
运行示意图如下:
在这里插入图片描述
虚拟机参数

# 最大垃圾收集停顿时间(毫秒)
-XX:MaxGCPauseMillis

# 设置吞吐量(0~100-XX:GCTimeRatio

# 自适应调节策略
-XX:UseAdaptiveSizePolicy

老年代垃圾收集器解析

Serial Old 收集器
Serial 收集器的老年代版本,单线程,使用“标记-整理”算法。主要用于客户端模式下的 HotSpot 虚拟机。
运行示意图如下:
在这里插入图片描述
Parallel Old 收集器
Parallel Scavenge 收集器的老年代版本,支持多线程并发收集,使用多线程和“标记-整理”算法实现。
运行示意图如下:在这里插入图片描述
在注重吞吐量或者处理器资源较为稀缺的场合,都可以考虑 Parallel Scavenge + Parallel Old 收集器的组合。
CMS 收集器
CMS(Concurrent Mark Sweep)收集器是一种以「获取最短回收停顿时间」为目标的收集器。
它基于“标记-清除”算法实现,运作过程分为四步:

  • 初步标记(CMS initial mark):只标记 GC Roots 能直接关联到的对象,速度很快;
  • 并发标记(CMS concurrent mark):从 GC Roots
    遍历整个对象图,耗时较长,但无需停顿用户线程(可与用户线程并发执行);
  • 重新标记(CMS remark):修正并发标记期间,因用户线程导致标记产生变动的标记记录;
  • 并发清除(CMS concurrent sweep):清理删除标记阶段判断的已经死亡的对象,可与用户线程并发执行。

运行示意图如下:
在这里插入图片描述
目前很大一部分 Java 应用集中在互联网网站或者 B/S 系统的服务上,这类应用尤其重视服务的响应速度,希望系统停顿时间最短,以给用户带来较好的体验。CMS 收集器非常符合这类应用的需求。
CMS 的主要优缺点

  • 主要优点:并发收集、低停顿
  • 主要缺点
    • 对处理器资源非常敏感,降低吞吐量。
    • 无法处理“浮动垃圾”,有可能出现“Concurrent Mode Failure”失败而导致另一次完全 Stop The World 的
      Full GC 的产生。
    • 内存空间碎片问题

浮动垃圾(Floating Garbage):在 CMS 的并发标记和并发清理阶段,用户线程是还在继续运行的,程序在运行自然就还会伴随有新的垃圾对象不断产生,但这一部分垃圾对象是出现在标记过程以后,CMS 无法在当次收集中处理掉它们,只好留待下一次垃圾收集时再清理掉。这部分垃圾就是“浮动垃圾”。
虚拟机参数

# 使用 CMS 收集器
-XX:+UseConcMarkSweepGC

# 老年代使用空间的比例(需根据实际情况权衡)
-XX:CMSInitiatingOccupancyFraction=80

# Full GC 时开启内存碎片的合并整理
-XX:+UseCMSCompactAtFullCollection

新生代和老年代垃圾收集器

G1 收集器
G1收集器-标记整理算法
JDK1.7后全新的回收器, 用于取代CMS收集器。
G1收集器的优势:

  • 独特的分代垃圾回收器,分代GC: 分代收集器, 同时兼顾年轻代和老年代;
  • 使用分区算法, 不要求eden, 年轻代或老年代的空间都连续;
  • 并行性: 回收期间, 可由多个线程同时工作, 有效利用多核cpu资源;
  • 空间整理: 回收过程中, 会进行适当对象移动, 减少空间碎片;
  • 可预见性: G1可选取部分区域进行回收, 可以缩小回收范围, 减少全局停顿。

G1收集器的运作大致可划分为一下步骤:
在这里插入图片描述
G1收集器的阶段分以下几个步骤:

  • 初始标记(它标记了从GC Root开始直接可达的对象);
  • 并发标记(从GC Roots开始对堆中对象进行可达性分析,找出存活对象);
  • 最终标记(标记那些在并发标记阶段发生变化的对象,将被回收);
  • 筛选回收(首先对各个Regin的回收价值和成本进行排序,根据用户所期待的GC
  • 停顿时间指定回收计划,回收一部分Region)。

查看jdk1.8x默认垃圾收集器

方式一:通过java -XX:+PrintCommandLineFlags -version命令查看

C:\Users\张江丰>java -XX:+PrintCommandLineFlags -version
-XX:InitialHeapSize=132392832 -XX:MaxHeapSize=2118285312 -XX:+PrintCommandLineFlags -XX:+UseCompressedClassPointers -XX:+UseCompressedOops -XX:-UseLargePagesIndividualAllocation -XX:+UseParallelGC
java version "1.8.0_101"
Java(TM) SE Runtime Environment (build 1.8.0_101-b13)
Java HotSpot(TM) 64-Bit Server VM (build 25.101-b13, mixed mode)

方式二:通过jconsole查看
在这里插入图片描述
注:PS MarkSweep(Serial Old) PS Scavenge(Parallel Scavenge)

在JVM中是+XX配置实现的搭配组合:

介绍了JVM中的垃圾回收器,主要包括串行回收器、并行回收器以及CMS回收器、G1回收器。他们各自都有优缺点,通常来说你需要根据你的业务,进行基于垃圾回收器的性能测试,然后再做选择。下面给出配置回收器时,经常使用的参数:

  • UseSerialGC 虚拟机运行在Client模式下的默认值,表示用 Serial + Serial Old 的收集器组合进行内存回收
  • UseParNewGC 表示用 ParNew + Serial Old 的收集器组合进行内存回收
  • UseConcMarkSweepGC 表示用 “ParNew” + “CMS” + "Serial Old"的收集器组合,Serial Old 收集器作为CMS收集器出现Concurrent Mode Failure失败后的后备收集器
  • UseParallelGC 虚拟机运行在Server模式下的默认值,表示用 Parallel Scavenge + Serial Old的收集器组合进行内存回收
  • UseParallelOldGC 表示用 Parallel Scavenge + Parallel Old的收集器组合进行内存回收
参考资料:

《深入理解Java虚拟机》

发布了32 篇原创文章 · 获赞 53 · 访问量 2467

猜你喜欢

转载自blog.csdn.net/qq_41714882/article/details/104439674