jvmjava中的经典垃圾回收器

周二鸭      2022-04-04     558

关键词:

从不同角度分析垃圾收集器,可以将其划分为不同的模型。

按线程数分,可以分为串行垃圾回收器和并行垃圾回收器;按照工作模式分,可以分为并发式垃圾回收器和独占式垃圾回收器;按碎片处理方式可分为压缩式垃圾回收器和非压缩式垃圾回收器;而按工作的内存区间,又可分为新生代垃圾回收器和老年代垃圾回收器。本文就基于工作的内存区间划分,来介绍七种经典的垃圾回收器,下图是它们的工作区间以及搭配方式。

Young generation

Serial 收集器

看名字就能猜到,这个收集器是一个单线程工作的收集器,但是它的“单线程”的意义并不仅仅是说明它只会使用一个处理器或一条收集线程去完成垃圾收集工作,更重要的是强调在它进行垃圾收集时,必须暂停其他所有工作线程,直到它工作结束。同时,其采用的是标记复制算法

Serial 是 JDK 1.3.1 之前新生代的唯一选择,虽然看起来这个垃圾收集器好像老而无用了。但是事实上它依然是 HotSpot 虚拟机运行在客户端模式下的默认新生代垃圾收集器,有着优于其他收集器的地方,那就是简单而高效(与其他收集器的单线程相比),对于内存资源受限的环境,它是所有收集器里额外内存消耗(Memory Footprint)最小的;

ParNew 收集器

ParNew 收集器实际上是 Serial 收集器的多线程并行版本,除了同时使用多条线程进行垃圾收集之外,其余的行为包括 Serial 收集器可用的所有控制参数、收集算法、Stop The World、对象分配规则、回收策略等都与 Serial 收集器完全一一致。

ParNew 收集器除了支持多线程并行收集外,其他与 Serial 收集器相比并没有太多的创新之处,但它却是不少运行在服务端模式下的 HotSpot 虚拟机,尤其是 JDK 7 之前的遗留系统首选的新生代收集器,其中有一个与功能、性能无关但其实很重要的原因:除了 Serial 收集器外,目前只有它能与 CMS 收集器配合工作

ParNew 收集器在单核心处理器的环境中绝对不会有比 Serial 收集器更好的效果。它默认开启的收集线程与处理核心数量相同,在处理器核心非常多的环境下,可以使用 -XX:ParallelGCThreads 来限制垃圾回收器的线程数。

Parallel Scavenge 收集器

Parallel Scavenge 收集器也是一款新生代收集器,同样是基于标记-复制算法实现的收集器,其从表面上看与 ParNew 十分相似,但它的关注点与其他收集器不同,CMS 等收集器的关注点是尽可能地缩短垃圾收集时用户线程的停顿时间,而 Parallel Scavenge 收集器的目标则是达到一个可控制的吞吐量(Throughput)。

所谓吞吐量就是处理器用于运行用户代码的时间与处理器总消耗的时间的比值,即:

\[吞吐量 = \frac{运行用户代码时间}{运行用户代码时间 + 运行垃圾收集时间} \]

Tenured generation

Serial Old 收集器

Serial Old 是 Serial 收集器的老年代版本,同样也是一个单线程工作的收集器,使用标记整理算法

这个收集器的主要意义也是提供客户端模式下的 HotSpot 虚拟机使用。如果在服务端模式下,它也可能有两种用途:一种是在 JDK 5 以前的版本中与 Parallel Scavenge 收集器搭配使用,另外一种就是做为 CMS 收集器发生失败时的后备预案,在并发收集发生 Concurrent Mode Failure 时使用。

Parallel Old 收集器

Parallel Old 是 Parallel Scavenge 收集器的老年代版本,支持多线程并发收集,基于标记整理算法

其主要与 Parallel Scavenge 做搭配。

CMS 收集器

CMS(Concurrent Mark Sweep)收集器是一种以获取最短回收停顿时间为目标的收集器。从名字上就可以看出 CMS 收集器是基于标记-清除算法实现的,它的运作过程相对于前面几种收集器来说要更复杂一些,整个过程分为四个步骤,包括:

  1. 初始标记(CMS initial mark)
  2. 并发标记(CMS concurrent mark)
  3. 重新标记(CMS remark)
  4. 并发标记(CMS concurrent sweep)

其中并发标记以及重新标记这两个步骤仍然需要“Stop The World”。

初始标记仅仅只是标记一下GC Roots能直接关联到的对象,速度很快;

并发标记就是从GC Roots的直接关联对象开始遍历整个对象图的过程,这个过程耗时很长但是不需要停顿用户线程,可以与垃圾收集线程一起并发运行;

而重新标记阶段则是为了修正并发标记期间,因用户程序继续运作而导致标记产生变动的那一部分对象的标记记录,这个阶段的停顿时间通常会比初始标记阶段稍微长一些,但也远比并发标记阶段的时间短;

最后是并发清除阶段,清除删除掉标记阶段判断的已经死亡的对象,由于不需要移动存活对象,所以这个阶段也是可以与用户线程并发进行的。

CMS 的优点很明显:并发收集、低停顿。但它也有很明显的缺点:

  • CMS收集器对处理器资源非常敏感。事实上,面向并发设计的程序都对处理器资源比较敏感。在并发阶段,它虽然不会导致用户线程停顿,但却会因为占用了一部分线程(或者说处理器的计算能力)而导致应用线程变慢,降低总吞吐量。

  • 由于CMS收集器无法处理“浮动垃圾”(Floating Garbage),有可能出现”Concurrent Mode Failure“失败进而导致另一次完全”Stop The World“的 Full GC 的产生。

    浮动垃圾:并发清理阶段用户线程还在运行,这段时间内就可能产生新的垃圾,新的垃圾在此次 GC 无法清除,只能等到下次清理。这些垃圾有个专业的名词:浮动垃圾;

  • CMS 是一款基于”标记-清除“的算法实现的垃圾收集器,这意味着收集结束时会有大量的空间碎片产生。空间碎片过多时,将会给大对象的分配带来很大的麻烦,往往会出现老年代还有很多剩余空间,但就是无法找到足够大的连续空间来分配当前对象。

Garbage First

为解决CMS算法产生空间碎片和其它一系列的问题缺陷,HotSpot提供了另外一种垃圾回收策略,G1(Garbage First)算法,通过参数-XX:+UseG1GC来启用,该算法在JDK 7u4版本被正式推出,官网对此描述如下:

The Garbage-First (G1) collector is a server-style garbage collector, targeted for multi-processor machines with large memories. It meets garbage collection (GC) pause time goals with a high probability, while achieving high throughput. The G1 garbage collector is fully supported in Oracle JDK 7 update 4 and later releases. The G1 collector is designed for applications that:

  • Can operate concurrently with applications threads like the CMS collector.

  • Compact free space without lengthy GC induced pause times.

  • Need more predictable GC pause durations.

  • Do not want to sacrifice a lot of throughput performance.

  • Do not require a much larger Java heap.

在 G1 算法中,采用了另外一种完全不同以往的组织堆内存,堆内存被划分为多个大小相等的内存块(Region),每个Region是逻辑连续的一段内存,结构如下:

每个Region被标记了E、S、O和H,说明每个Region在运行时都充当了一种角色,其中H是以往算法中没有的,它代表Humongous,这表示这些Region存储的是巨型对象(humongous object,H-obj),当新建对象大小超过Region大小一半时,直接在新的一个或多个连续Region中分配,并标记为H。

G1 中提供了三种模式垃圾回收模式,young GC、mixed GC 和 full GC,在不同的条件下被触发。

Young GC

发生在年轻代的GC算法,一般对象(除了巨型对象)都是在eden region中分配内存,当所有eden region被耗尽无法申请内存时,就会触发一次 Young GC,这种触发机制和之前的 young GC 差不多,执行完一次 Young GC,活跃对象会被拷贝到survivor region或者晋升到old region中,空闲的region会被放入空闲列表中,等待下次被使用。

Mixed GC

当越来越多的对象晋升到老年代old region时,为了避免堆内存被耗尽,虚拟机会触发一个混合的垃圾收集器,即 mixed gc,该算法并不是一个 Old GC,除了回收整个 Young region,还会回收一部分的 Old Region,这里需要注意:是一部分老年代,而不是全部老年代,可以选择哪些 Old region 进行收集,从而可以对垃圾回收的耗时时间进行控制。

mixed GC 的执行过程有点类似 CMS,主要分为以下几个步骤:

  1. initial mark: 初始标记过程,整个过程 STW,标记了从GC Root可达的对象
  2. concurrent marking: 并发标记过程,整个过程 GC collector线程与应用线程可以并行执行,标记出GC Root可达对象衍生出去的存活对象,并收集各个Region的存活对象信息
  3. remark: 最终标记过程,整个过程 STW,标记出那些在并发标记过程中遗漏的,或者内部引用发生变化的对象
  4. clean up: 垃圾清除过程,如果发现一个Region中没有存活对象,则把该 Region 加入到空闲列表中

Full GC

如果对象内存分配速度过快,Mixed GC 来不及回收,导致老年代被填满,就会触发一次 Full GC,G1 的 Full GC 算法就是单线程执行的 serial old gc,会导致异常长时间的暂停时间,需要进行不断的调优,尽可能的避免 Full GC.

jvm垃圾回收篇(经典垃圾回收器讲解)(代码片段)

经典垃圾回收器讲解1.Serial垃圾收集器2.ParNew垃圾收集器3.Parallel垃圾收集器4.CMS垃圾收集器5.G1垃圾收集器1.基本介绍2.四大特性3.不足之处4.参数设置5.适用场景6.什么是Region?7.什么是记忆集?8.G1回收过程9.G1回收详细步骤6.... 查看详情

经典面试题|讲一下垃圾回收器都有哪些?

垃圾回收器有哪些?是一个高频的面试题,那本文就详细来解答这个问题。因为不同的厂商(IBM、Oracle),实现的垃圾回收器各不相同,而本文要讨论的是Oracle的HotSpot虚拟机所使用的垃圾回收器。常用垃圾回收器,如下图所示... 查看详情

java虚拟机jvmjava堆方法区java栈

java堆是java应用程序最密切的内存空间。差点儿全部的对象都存在堆中。java堆全然自己主动化管理,通过垃圾回收机制,垃圾对象会自己主动清理。不须要显式释放。依据java垃圾回收机制的不同。java堆可能有不同的结构。最常... 查看详情

经典面试题:聊一聊垃圾回收算法

关于垃圾回收算法的这道面试题,几乎是所有3年以上的Java面试中必问的题目,甚至有些好一点的公司会在校招时问到面试者。那么本文就系统的讲一下垃圾回收的算法,和Hotspot虚拟机执行垃圾回收的一些实现细节,比如安全点... 查看详情

jvm垃圾回收

...圾回收的概念和其算法垃圾回收(GarbageCollection,简称GC),GC中的垃圾特指存于内存中,不会再被使用的对象,而回收就是相当于把垃圾“倒掉”。垃圾回收有很多算法,如引用计数法,标记压缩法,复制算法,分代、分区的思想。... 查看详情

03_垃圾回收

【简述】垃圾回收GC(GarbageCollection),GC中的垃圾,特指存于内存中不会再使用的对象,回收相当于清除垃圾。垃圾回收有很多种算法,如:引用计数法、标记压缩法、复制算法、分代分区思想。[引用计数法]是比较古老经典的... 查看详情

java重点知识汇总(包含java基础jvmjava并发)(代码片段)

...其各自的特点GC类型、触发时机和对象晋升时机常见垃圾回收器JVM调优与GC优化JVM类加载机制JVM类加载器与双亲委派模型对象的创建过程([参考JavaGuide](https://github.com/Snailclimb/JavaGuide))三、Java并发重点知识汇总线程的状态与转换Java... 查看详情

java重点知识汇总(包含java基础jvmjava并发)(代码片段)

...其各自的特点GC类型、触发时机和对象晋升时机常见垃圾回收器JVM调优与GC优化JVM类加载机制JVM类加载器与双亲委派模型对象的创建过程([参考JavaGuide](https://github.com/Snailclimb/JavaGuide))三、Java并发重点知识汇总线程的状态与转换Java... 查看详情

深入理解java虚拟机gc垃圾回收-经典垃圾收集器

文章目录前言一、Serial收集器(标记-复制算法)二、ParNew收集器(标记-复制算法)三、ParallelScavenge收集器(标记-复制算法)四、SerialOld收集器(标记-整理算法)五、ParallelOld收集器(标记-整理算法)六、CMS收集器(标记-清除算法)七、GarbageFi... 查看详情

jvm虚拟机:jvm垃圾回收机制概念及其算法(代码片段)

...GarbageCollection)GC,需要先澄清什么是垃圾,类比日常生活中的垃圾,我们会把他们丢入垃圾箱,然后倒掉。GC中的垃圾,特指存于内存中、不会再被使用的对象,儿回收就是相当于把垃圾“倒掉”。垃圾回收有很多中算法:如引... 查看详情

jvm及垃圾回收机制原理

JVMJava虚拟机Java虚拟机(Javavirtualmachine,JVM)是运行Java程序必不可少的机制。JVM实现了Java语言最重要的特征:即平台无关性。原理:编译后的Java程序指令并不直接在硬件系统的CPU上执行,而是由JVM执行。JVM屏蔽了与具体平台相... 查看详情

jvm垃圾回收篇(垃圾回收器基本概述)(代码片段)

垃圾回收器基本概述1.垃圾回收器分类2.垃圾回收器的性能指标3.垃圾回收器的发展史4.经典的垃圾回收器1.垃圾回收器分类按线程数分串行垃圾回收器串行回收指的是在同一时间段内只允许有一个CPU用于执行垃圾回收操作,此... 查看详情

jvm中的垃圾回收

一、垃圾回收的概念   Java中的内存回收即Jvm运行时的内存的回收,需要回收的区域有方法区和Java堆。由于程序计数器,Java虚拟机栈和本地方法栈在方法结束或者是线程结束时会自动进行回收所以无须考虑回收。为什么需要... 查看详情

jvm--14---垃圾回收----概述

...JVM整体架构Java和C++语言的区别关于垃圾收集有三个经典问题:1.什么是垃圾?垃圾是指==在运行程序中没有任何指针指向的对象==,这个对象就是需要被回收的垃圾。2.为什么需要GC?3.早期垃圾回收Java... 查看详情

深入浅知jvm(面试必备)

JVMJava虚拟机意义:跨平台把Java字节码转换成操作系统/CPU能够识别的二进制指令JVM区域内存划分堆方法区栈程序计数器JVM做的事情:类加载执行引擎(解释执行字节码)动态内存管理(申请内存/释放内存)... 查看详情

深入理解jvm(③)经典的垃圾收集器

...圾收集器就是内存回收的实践者。本次要介绍的是几款“经典”的垃圾收集器,之所以被称之为“经典”,是为了与几款目前仍处于实验状态,但是执行效果上哟革命性改进的高性能低延迟收集器区分开来,虽然算不上最先进的... 查看详情

javascript中的的垃圾回收机制

JavaScript中的的垃圾回收机制javascript的垃圾回收原理(1)、在javascript中,如果一个对象不再被引用,那么这个对象就会被GC回收; (2)、如果两个对象互相引用,而不再被第3者所引用,那么这两个互相引用的对象也会被回... 查看详情

java回收机制总结

...首先要明白什么是“垃圾”,垃圾回收机制是回收堆内存中的对象(具体的内存划分可以看:),对于栈中的对象是不需要回收机制去考虑的。在Java中堆内存中的对象是通过和栈内存中的引用相互关联,才被利用的。既然是对... 查看详情