Advertisement

JVM GC发展史

阅读量:

JVM GC发展史

  • 一、JVM垃圾收集机制
    • 一.1 单线程式回收机制
      • 一.2 ParNew回收机制
      • 一.3 多线程式清除回收机制
      • 一.4 单线程式旧回收机制
      • 一.5 多线程式旧回收机制
      • 一.6 CMS回收机制
        • G0回收机制(基于-XX:+UseG0GC选项)
        • G1回收机制(基于-XX:+UseG1GC选项)
      • 一.7 ZGC回收机制
  • 总结与展望

1、JVM垃圾收集器

在这里插入图片描述

经历了多年的发展与演进,jvm经历了多年的发展与演进,其中一些已逐渐被 newer JDK versions淘汰,特别是近 couple of years中,主要聚焦于G1和ZGC容器优化,其他容器则要么被移除要么被废弃。目前市场上许多项目仍沿用 JDK 1.8作为基准版本,例如在面试中常见的是围绕 JDK 1.8的各种问题进行考察,包括但不限于默认使用的收集器类型。例如在面试中常见的是围绕 JDK 1.8的各种问题进行考察,特别是关于默认收集器的问题。例如,jdk默认的是 Parallel Scavenge 收集器,默认情况下可能同时运行 Parallel Scavenge 和 Parallel Old GC组合以提高性能

1.1、Serial收集器

Serial(串行)收集器收集器是最基本、历史最悠久的垃圾收集器了(在jdk1.3.1版本之前Serial是唯一一个年轻代的GC容器)。大家看名字就知道这个收集器是一个单线程收集器了。它的 “单线程” 的意义不仅仅意味着它只会使用一条垃圾收集线程去完成垃圾收集工作,更重要的是它在进行垃圾收集工作的时候必须暂停其他所有的工作线程( “Stop The World” ),直到它收集结束。这就意味着每次GC时都会给用户带来一定的卡顿现象造成不良的用户体验。他相比于其他收集器也有一定的优点:简单而高效(与其他收集器的单线程相比),Serial收集器由于没有线程交互的开销,自然可以获得很高的单线程收集效率。
新生代采用复制算法,老年代采用标记-整理算法。

在这里插入图片描述

1.2、ParNew收集器

可以说 ParNew 是 Serial 的一个增强版本,在其多线程式垃圾回收功能上具有独特优势。它的核心特性包括控制参数设置、收集算法选择以及回收策略应用等均与之相同。该方案在多数基于 Server 模式的虚拟机环境中被普遍采用作为下一代垃圾回收方案,在没有使用 Standard 收集器的情况下,默认搭配使用该方案能够与 CMS 兼容运作。

1.3、Parallel Scavenge收集器

此收集器看起来与ParNew收集器在功能上相似性较高,但两者的侧重点存在差异性。Parallel Scavenge收集器将焦点放在吞吐量上,即通过高效率地利用CPU资源来实现较大的处理能力(CPU执行总时长-GC总时长)/CPU总时长)。而CMS等垃圾收集器则更关注提升用户体验,即减少用户线程因等待GC而产生的停滞时间(CPU执行总时长-GC总时长)/CPU总时长)。所谓吞吐量,即指CPU中用于运行用户代码的时间与CPU总消耗时间的比例值((CPU执行总时长-GC总时长)/CPU总时长)。有人可能会好奇为什么Parallel Scavenge无法与CMS相互协同工作,这里参考了本人的一篇博客文章 主要原因在于现有JDK默认配置下的Hotspot VM热点中存在多个GC组件的部分共享代码,其中包括一个基于分代式的GC框架结构,其中Serial/Serial Old/ParNew/CMS均位于该框架内;在该框架内,young collector与old collector之间可以任意组合使用,即所谓的"混搭使用"(mix-and-match)策略。然而Parallel Scavenge并未采用 hotspot VM默认配置下与其他GC通用共有的GC框架结构,因此无法与基于该框架结构运行的CMS兼容使用.新生代收集器采用复制算法来进行内存回收,而老年代集采用标记-整理算法来进行内存回收.

在这里插入图片描述

1.4、Serial Old收集器

这个类在JDK 1.5及更早版本中被设计为与ParallelScavenge收集器协同工作,并且作为CMS收集器的替代方案出现。该类主要包含两个应用场景:其一是在旧版本中配合ParallelScavenge完成垃圾回收;其二是作为CMS垃圾回收操作的一个备用方案使用。

1.5、 Parallel Old收集器

该方案采用_parallel garbage collector(PGC)作为核心机制,并特别针对高吞吐量场景进行了优化设计。通过引入multi-threaded架构并结合mark-and-sweep algorithm实现内存回收过程中的并行化处理,在保证系统稳定性的同时显著提升了运行效率。基于当前计算资源条件下可选方案包括_parallel garbage collector(PGC)与_parallel old generation garbage collector(POG)。两者均具备高效的内存管理能力,在实际应用中可分别对应不同对性能需求的关注点:对于对高吞吐量要求较高的场景推荐采用PGC方案;而对于希望平衡性能与开发复杂度的场景则推荐选择POG方案。

1.6、CMS收集器

CMS(Concurrent Mark Sweep)收集器是一种以获取最短回收停顿时间为目标的收集器。它而非常符合在注重用户体验的应用上使用,它是HotSpot虚拟机第一款真正意义上的并发收集器,它第一次实现了让垃圾收集线程与用户线程(基本上)同时工作。CMS收集器是一种 “标记-清除”算法实现的,它的运作过程相比于前面几种垃圾收集器来说更加复杂一些。
整个过程分为四个步骤:
初始标记:暂停所有其他的线程(STW),并记录下直接与root相连的对象(这个过程中速度会很快);
并发标记: 同时开启GC和用户线程,用一个闭包结构去记录可达对象,但在这个阶段结束后,这个闭包结构并不能保证包含所有的当前可达对象,什么意思呢(就是我在执行GC的时候可能用户线程也正在产生新的GC垃圾或者之前被标记为垃圾对象的有从新被引用了但是无法感知到)。所以这个算法里会跟踪记录这些发生引用更新的地方。
重新标记: 重新标记阶段就是为了修正并发标记期间因为用户陈旭继续运行而导致标记产生变动的那一部分对象的标记记录,这一阶段的停顿时间一般会比初始标记时间长些,但是远远比并发标记阶段的时间段(可以这样理解:你搬完家时,发现自己还有一些东西落在老房子里,然后要回去拿,这段时间是要比你搬家的时间短的多吧)。
并发清除: 开启用户线程,同时GC线程开始对未标记的区域做清扫。

在这里插入图片描述

从其名称便可判断它是一款卓越的垃圾回收器,在实际应用中表现出色。其主要优势在于支持多线程收集和低延迟运行。然而该算法存在以下明显缺陷:一是对硬件资源极度敏感,在运行过程中容易出现资源竞争现象;二是存在动态内存碎片问题,在特定工作负载下可能导致系统性能下降;三是该算法所采用的标记-清除模式可能导致最终的内存碎片问题较为严重。

1.6 G1收集器(-XX:+UseG1GC)

4.7 G1收集器(-XX:+UseG1GC)
G1 (Garbage-First)是一种用于服务器系统的垃圾回收工具。它主要适用于多处理器及大内存系统,并能在绝大多数情况下能够保证GC运行时的稳定性,并且具有很高的处理能力。

在这里插入图片描述

G1将Java堆划分为多个大小相等的独立区域(Region),虽然仍然保留新生代和老年代的概念,但这些区域不再是物理隔离的存在而是由多个Region共同构成。
大对象被分配到 Humongous 区域中进行存储时,并不会因无法找到足够的连续内存空间而导致垃圾回收提前启动下一次循环。
作为JDK 1.7中HotSpot虚拟机的重要进化特征之一,G1收集器具备以下显著特点:
通过多线程或多核处理器的强大处理能力,G1能够在较短的时间内完成停顿操作,从而减少了垃圾回收时对Java程序运行的影响。
尽管G1收集器能够独立管理GC堆而不依赖其他收集器,但它依然保留了一定程度上的分代收集机制。
与CMS算法不同,G1采用了全新的"标记整理"算法来进行整体垃圾回收,但在局部操作阶段则采用复制算法以提高效率。
相较于CMS算法,G1不仅追求低停顿时间,还能够建立精确的时间模型来预测停顿周期,从而让用户更加直观地了解垃圾回收的时间安排。
整个G1收集器的工作流程大致可分为以下几个关键阶段:
初始标记阶段:在此阶段,G1 GC对根节点进行标记处理,这一过程与常规年轻代垃圾回收的方法存在高度相似性。
并发标记阶段:在这一阶段,G1 GC会对整个堆中的存活对象进行可访问性检查。
最终标记阶段:该步骤类似于常规年轻代垃圾回收中的STW回填过程,有助于完成当前标记周期的所有标记工作。
清理回收阶段:在清理回收过程中,系统会对各个Region的价值和成本进行排序,并根据预设的时间参数来制定具体的回收策略;这一过程可以在不影响程序运行的情况下实现一定程度上的并发执行以进一步优化效率。

G1收集器后台运行时维护了一个优先级列表,在给定的时间限制内会最先处理具有最高回收价值的内存区域(这也是其名称Garbage-First源自)。该系统通过将内存划分为不同的区域并按优先级排序的内存回收机制确保了G1收集器能够在有限时间内实现高效的内存回收效率

G1垃圾收集分类
YoungGC
新对象进入Eden区
存活对象拷贝到Survivor区
存活时间达到年龄阈值时,对象晋升到Old区
MixedGC
不是FullGC,回收所有的Young和部分Old(根据期望的GC停顿时间确定old区垃圾收集的优先顺序)
global concurrent marking (全局并发标记)
Initial marking phase:标记GC Root,STW
Root region scanning phase:标记存活Region
Concurrent marking phase:标记存活的对象
Remark phase :重新标记,STW
Cleanup phase:部分STW
Full GC
就是全局(STW)。
相关参数
G1MixedGCLiveThresholdPercent Old区的region被回收的时候的存活对象占比
G1MixedGCCountTarget:一次global concurrent marking之后,最多执行Mixed GC的次数
G1OldCSetRegionThresholdPercent 一次Mixed GC中能被选入CSet的最多old区的region数量
触发的时机
InitiatingHeapOccupancyPercent:堆占有率达到这个值则触发global concurrent marking,默认45%
G1HeapWastePercent:在global concurrent marking结束之后,可以知道区有多少空间要被回收,在每次YGC之后和再次发生Mixed GC之前,会检查垃圾占比是否达到了此参数,只有达到了,下次才会发生Mixed GC

1.7、ZGC

在OpenJDK 11上对ZGC(作为实验版本)进行了概述。该工具被描述为一个具有扩展性和低延迟性的垃圾收集器。然而,在垃圾回收pause时间变得过长时,则可能导致应用程序响应时间受到影响。通过减少或大幅缩减垃圾回收pause的时间,则会使得Java成为一个更具吸引力的选择,并适用于更为广泛的场景。此外,在现代系统中可用的内存量持续增长的趋势下,请开发者们希望JVM能够以一种高效的方式充分地利用这些内存资源,并且尽量避免出现长时间GC pause的情况。具体而言,则建议将最大停顿时间控制在10ms以内

结束语

我对技术的理解较为浅薄,请各位前辈赐教。尽管目前个人能力还有待提升,但我将以更加积极的态度面对工作挑战。青年朋友,请继续加油!

全部评论 (0)

还没有任何评论哟~