垃圾回收器之CMS回收器和G1回收器

新生代老年代VM选项参数
SerialSerial Old-XX:UseSerialGC
ParNewSerial Old-XX:UseParNewGC
Parallel ScavengeSerial Old-XX:UseParallelGC
Parallel ScavengeParallel Old-XX:UseParallelOldGC
Parallel ScavengeCMS/Serial Old-XX:UseConcMarkSweepGC
G1G1-XX:+UseG1GC

串行收集器组合 Serial + Serial Old(单线程)
并行收集器组合 Parallel Scavenge + Parallel Old(多线程)
(JDK8默认的GC回收器是 Parallel Scavenge 和 Parallel Old)
(JDK9以后默认的GC回收器是 G1)

安全点(safepoint):

    程序执行时并非在所有地方都能停顿下来开始GC,只有在到达安全点时才能暂停。安全点的初始目的并不是让其他线程停下,而是找到一个稳定的执行状态。在这个状态下,Java虚拟机的堆栈都不会发生变化。这么一来,垃圾回收器便能够“安全”地执行可达性分析。
安全点的选定基本上是以程序“是否具有让程序长时间执行的特征”为标准进行选定的,“长时间执行”的最明显特征就是指令序列复用,例如方法调用,循环跳转,异常跳转等,具有这些功能的指令才会产生安全点。

CMS(Concurrent Mark Sweep)收集器是一种以获取最短回收停顿时间为目标的收集器,因为CMS工作时,GC工作线程与用户线程可以并发执行,以此来达到降低收集停顿时间的目的。
CMS 仅作用于老年代的收集,基于“标记-清除”算法,当老年代使用率达到92%会触发GC
CMS运行过程:
  1. 初始标记(GCRoots 能直接关联到的对象,速度快,Stop The World 停止所有进程)
  2. 并发标记(进行GC Root Tracing 可达性分析)
  3. 重新标记(修正并发标记期间因用户程序继续运作而导致的变动,速度快,Stop The World 停止所有进程)
  4. 并发清除(与用户进程并发运行)

整个过程中只有两次短暂的暂停,达到了近似并发的目的。

CMS的优点:并发收集,低停顿。
CMS的缺点:1. 对 CPU 资源太敏感
             2. CMS 收集器无法处理浮动垃圾。

(所谓的“浮动垃圾”,就是在并发标记阶段,由于用户程序在运行,那么自然就会有新的垃圾产生,这部分垃圾被标记过后,CMS 无法在当次集中处理它们(为什么?原因在于 CMS 是以获取最短停顿时间为目标的,自然不可能在一次垃圾处理过程中花费太多时间),只好在下一次 GC 的时候处理。这部分未处理的垃圾就称为“浮动垃圾”。由于垃圾收集阶段用户线程还需要运行,那就不能等老年代几乎全满了再收集,一般达到 92%时就开始收集,而 CMS 运行期间预留的内存无法满足程序需要,就会出现“Concurrent Mode Failure”,此时将启动备用方案 serial old)

             3. 基于“标记-清除”算法,会导致大量的空间碎片的产生。

在这里插入图片描述

G1(Garbage-First)收集器重新定义了堆空间,打破了原有的分代模型,将堆分为一个个区域(Region)。这么做的目的是在进行收集时不必在全堆范围内进行,虽然还保留新生代和老年代的概念,但新生代和老年代不再是物理隔离的了,他们都是Region(不需要连续)的集合。

在这里插入图片描述
G1 跟踪各个 Region 里面的垃圾堆积价值大小(回收所获得的空间大小以及回收所需的时间),在后台维护一个优先列表,每次优先收集价值最大的 Region(所以叫 GarbageFirst),从而保证了 G1 在有限时间内可以获取尽可能高的收集效率。

G1 的 YoungGC 就是将 E 区和 S 区复制到灰色的空白区。
G1 中有 Humongous 区(巨大区)用于存放比标准块大 50%的对象

G1回收过程:
  1. 初始标记 (Stop The World)
  2. 并发标记
  3. 最终标记 (Stop The World)
  4. 筛选回收(Stop The World,首先对各个Region的回收价值和成本进行排序,更具用户所期望的GC停顿时间来制定回收计划。因为只回收一部分Region,时间是用户控制的,而且停顿用户线程将大幅提高收集效率)
    在这里插入图片描述
G1的特点:1. 并行与并发(G1能充分利用多CPU,使用多个CPU来缩短停顿时间)
           2. 分代收集(不需要其他收集器配合)
           3. 空间整合(G1从整体上看是基于“标记-整理”算法实现的,从局部(两个Region之间)上看是基于“复制”算法实现的。意味着G1运行期间不会产生内存碎片,收集后能提供规整的可用内存。这种特性有利于程序长时间运行,分配大对象时不会因为无法找到连续内存空间而提前触发下一次GC)
           4. 可预测的停顿(G1回收的第4步,它是“选择一些内存块”,而不是整代内存来回收,这是G1跟其它GC非常不同的一点,其它GC每次回收都会回收整个Generation的内存(Eden, Old), 而回收内存所需的时间就取决于内存的大小,以及实际垃圾的多少,所以垃圾回收时间是不可控的;而G1每次并不会回收整代内存,到底回收多少内存就看用户配置的暂停时间,配置的时间短就少回收点,配置的时间长就多回收点,伸缩自如。)

(-XX:MaxGCPauseMillis=200 为最大GC暂停时间设置一个指标。这是一个软目标,Java虚拟机将尽最大努力实现它。因此,暂停时间目标有时候可能不会达到。默认值是200毫秒。 )

卡表(Card Table):

    在每个分区内部又被分成了若干个大小为512 Byte卡片(Card),标识堆内存最小可用粒度所有分区的卡片将会记录在全局卡片表(Global Card Table)中,分配的对象会占用物理上连续的若干个卡片,当查找对分区内对象的引用时便可通过记录卡片来查找该引用对象。每次对内存的回收,都是对指定分区的卡片进行处理。维护一个全局卡片表,用来存储每张卡的一个标识位,这个标识位代表对应的卡是否可能存在有指向新生代对象的引用。如果可能存在,那么我们就认为这张卡是脏的。在进行Minor GC的时候,我们便可以不用扫描整个老年代,而是在卡表中寻找脏卡,并将脏卡中的对象加入到Minor GC的GCRoots里。当完成所有脏卡的扫描之后,Java虚拟机便会将所有脏卡的标识位清零。
卡表能用于减少老年代的全堆空间扫描,这能很大的提升GC效率。

◆ Java提供了一个为我们各种获取JVM信息的工厂类ManagementFactory,使用可以参考https://blog.csdn.net/dream_broken/article/details/49759043

 
 

参考:部分资料来源于网络

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值