jvm垃圾回收器-内存回收的具体实现【7种经典垃圾回收器】

垃圾收集器概述

  • 如果说收集算法是内存回收的方法论,那么垃圾收集器就是内存回收的具体实现。

  • java虚拟机规范中对垃圾收集器应该如何实现并没有任何规定,因此不同的厂商、不同的虚拟机所提供的垃圾收集器都可能会有很大的差别请添加图片描述

  • 如上图,展示了7中不同分代的收集器,如果两个收集器之间存在连线,就说明他们可以搭配使用。虚拟机所处的区域,则表示它是属于新生代收集器还是老年代收集器。接下来就对上面的垃圾收集器一一介绍,重点分析的CMS和G1这两相对复杂的收集器,了解他们的部分运作细节

  • 吞吐量(throughput)

    • 吞吐量就是CPU用于运行用户代码的时间与CPU总消耗时间的比值,即吞吐量 = 运行用户代码时间 / (运行用户代码时间 + 垃圾收集时间)

    • 高吞吐量的情况下,应用程序能容忍较高的暂停时间,因此高吞吐量的应用程序由更长的时间基准,快速响应是不必考虑的

  • 暂停时间(pause time)
    暂停时间是指一个时间段内应用程序线程暂停,让GC线程执行的状态

Serial 收集器

  • Serial收集器(Serial + Serial Old)的主要特点是单线程回收资源。当需要执行垃圾回收时,程序会暂停一切工作(又称为Stop The World,STW),使用复制算法完成垃圾清理工作。

  • 优点:

    • 简单高效,是Client模式下默认的垃圾收集器; 对于资源受限的环境,比如单核(例如Docker中设置单核),单线程效率较高;
    • 内存小于一两百兆的桌面程序中,交互有限,则有限的STW是可以接受的。
  • 缺点:

    • 垃圾回收速度较慢且回收能力有限,频繁的STW会导致较差的使用体验。
    • 请添加图片描述

Serial Old 收集器

  • 老年代的收集器,与Serial一样是单线程,不同的是算法用的是标记-整理(Mark-Compact)。
  • 因为老年代里面对象的存活率高,如果依旧是用复制算法,需要复制的内容较多,性能较差。并且在极端情况下,当存活为100%时,没有办法用复制算法。所以需要用Mark-Compact,以有效地避免这些问题。
  • 请添加图片描述

ParNew 收集器

  • ParNew同样用于新生代,是Serial的多线程版本,并且在参数、算法(同样是复制算法)上也完全和Serial相同。

  • Par是Parallel的缩写,但它的并行仅仅指的是收集多线程并行,并不是收集和原程序可以并行进行。ParNew也是需要暂停程序一切的工作,然后多线程执行垃圾回收。

  • 因为是多线程执行,所以在多CPU下,ParNew效果通常会比Serial好。但如果是单CPU则会因为线程的切换,性能反而更差。

  • 请添加图片描述

ParallelScavenger(PS) 收集器

  • 新生代的收集器,同样用的是复制算法,也是并行多线程收集。与ParNew最大的不同,它关注的是垃圾回收的吞吐量。(吞吐量在上文概述里面有介绍)

  • Parallel Scavenge收集器提供两个参数控制垃圾回收的执行:

    • -XX:MaxGCPauseMillis,最大垃圾回收停顿时间。这个参数的原理是空间换时间,收集器会控制新生代的区域大小,从而尽可能保证回收少于这个最大停顿时间。简单的说就是回收的区域越小,那么耗费的时间也越小。
      所以这个参数并不是设置得越小越好。设太小的话,新生代空间会太小,从而更频繁的触发GC。
    • -XX:GCTimeRatio,垃圾回收时间与总时间占比。这个是吞吐量的倒数,原理和MaxGCPauseMillis相同。 因为Parallel Scavenge收集器关注的是吞吐量,所以当设置好以上参数的时候,同时不想设置各个区域大小(新生代,老年代等)。可以开启**-XX:UseAdaptiveSizePolicy**参数,让JVM监控收集的性能,动态调整这些区域大小参数。

ParalleOld(PO) 收集器

  • 应用于老年代,多线程的。一样有STW。
  • 使用的mark-compact算法,标价压缩,就是先把有用的都标记一下,然后边清理垃圾边整理。还是需要遍历两次,第一次标记,第二次清除和压缩,这种算法效率会低一些,但不会产生碎片化,也没有像拷贝算法一样浪费内存空间。
  • 请添加图片描述

CMS收集器

  • 同样是老年代的收集器。它关注的是垃圾回收最短的停顿时间(低停顿),在老年代并不频繁GC的场景下,是比较适用的。

  • 命名中用的是concurrent,而不是parallel,说明这个收集器是有与工作执行并发的能力的。MS则说明算法用的是Mark
    Sweep算法。

  • 来看看具体地工作原理。CMS整个过程比之前的收集器要复杂,整个过程分为四步:

    • 初始标记阶段:开始一个短暂的STW,然后进行初始标记,初始标记只标记根节点能直接关联到的对象,所以这个STW时间很短。这个阶段是单线程的。

    • 并发标记阶段:据说GC大部分时间都浪费在这,所以这一步是和工作线程同时运行的。一边产生垃圾,一边标记垃圾。

    • 重新标记阶段:开始一个短暂的STW,把在并发标记阶段,工作线程产生的垃圾重新标记一下,这个STW时间也很短。这个阶段是多线程的。

    • 并发清理阶段:工作线程和垃圾回收线程同时运行,把这个时候工作线程产生的垃圾叫做浮动垃圾,浮动垃圾就要等到下一次CMS清理了。

  • CMS的最大问题:CMS会使内存碎片化,老年代产生了很多的碎片,然后从年轻代过来的对象无法找到空间,造成了promotion failed。这时候,CMS既没有机会进行垃圾回收,又放不下新来的对象,在这种情况下,CMS会调用SerialOld来进行垃圾回收。这是一件很恐怖的事情。

  • 请添加图片描述

G1 收集器

  • G1在逻辑上分代,在物理上不分代。G1引入了分而治之的思想,把内存分为一个一个的小块(region)。每个region逻辑上属于下面四种分代中的一种。

  • 四种分代:

    • Old区:老对象

    • b.Survivor区:存活对象

    • c.Eden区:新生对象

    • d.Humongous区:大对象,如果这个对象特别大,可能会跨两个region。
      请添加图片描述

  • G1提供了两种GC模式,Young GC以及Mixed GC,两种GC都会STW。

  • 两种GC模式:

    • Young GC,关注于所有年轻代的Region,通过控制收集年轻代的Region个数,从而控制GC的回收时间。
    • Mixed GC,关注于所有年轻代的Region,并且加上通过预测计算最大收益的若干个老年代Region。
  • 整体的执行流程:

    • 初始标记(initial mark),标记了从GC Root开始直接关联可达的对象。STW(Stop the World)执行。
    • 并发标记(concurrent marking),并发标记初始标记的对象,此时用户线程依然可以执行。
    • 最终标记(Remark),STW,标记再并发标记过程中产生的垃圾。
    • 筛选回收(Live Data Counting And Evacuation),评估标记垃圾,根据GC模式回收垃圾。STW执行。
      请添加图片描述
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

little Chen1

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值