OpenJDK时代更迭,CMS落寞与新王G1GC的崛起

少于 1 分钟阅读

本文主要讲解G1GC和CMS两者的区别。

善始善终的GC算法 - CMS

CMS算法原理

JDK 17 LTS已经彻底移除此GC算法.

CMS算法的核心思想是通过将垃圾回收过程拆分为多个阶段来减少垃圾回收对应用程序执行的影响,这些阶段包括:

  1. 初始标记阶段:在此阶段中,垃圾回收器仅扫描可达对象和GC Roots(如静态变量、本地变量、活动线程的堆栈中的引用)来确定哪些对象是需要被保留的。此阶段需暂停应用程序。

  2. 并发标记阶段:在此阶段中,垃圾回收器扫描所有的对象,并且跟踪所有的引用(包括被标记为可达的对象),同时应用程序在运行。

  3. 重新标记阶段:在此阶段中,GC运行在停止所有应用程序线程的情况下,以便找到在并发标记期间发生的新引用,并对其进行标记。这个阶段需要关闭应用程序线程,但持续的时间比初始标记阶段更短。

  4. 并发清除阶段:在此阶段中,GC运行在应用程序线程的同时释放以这些程序为根的所有已标记为不可达的对象。

  5. 失败保护:如果在并发标记或并发清除期间发现分配失败或分配缓慢,则进入失败保护阶段。在此阶段,GC暂停应用程序线程,使清除过程继续进行,并在必要时重新开始整个垃圾回收过程。

在CMS算法中,应用程序线程与垃圾回收线程并发执行,从而尽可能减少应用程序的停顿时间。但需要注意的是,CMS会消耗一部分的处理器资源,因此需要在性能和吞吐量之间做出权衡。

CMS算法的流程

下面是CMS算法执行的大体流程:

graph LR;
    A[初始化GC] --> B[初始标记]
    B --> C[并发标记]
    C --> D[重新标记]
    D --> E[并发清除]
    E --> F[失败保护]

注:箭头的方向从上到下,表示流程的先后顺序。

CMS算法的重要参数

以下是一些关键的CMS算法参数和示例代码:

  1. -XX:CMSInitiatingOccupancyFraction:触发执行CMS的占用率百分比。默认为68。

    1
    
    -XX:CMSInitiatingOccupancyFraction=70
    
  2. -XX:+UseCMSInitiatingOccupancyOnly:表示仅在CMS触发执行时才调用垃圾回收器。默认为false。

    1
    
    -XX:+UseCMSInitiatingOccupancyOnly
    
  3. -XX:+UseCMSCompactAtFullCollection:在执行完一次Full GC的时候,对整个Heap进行压缩,减少Heap的碎片。

    1
    
    -XX:+UseCMSCompactAtFullCollection
    
  4. -XX:CMSFullGCsBeforeCompaction:表示执行多少次Full GC之后,就会执行一次Heap压缩。

    1
    
    -XX:CMSFullGCsBeforeCompaction=3
    
  5. -XX:ConcGCThreads:并发执行GC的线程数。

    1
    
    -XX:ConcGCThreads=2
    
  6. -XX:-CMSConcurrentMTEnabled:关闭CMS的多线程并发执行。默认为true。

    1
    
    -XX:-CMSConcurrentMTEnabled
    

以上参数可以通过在启动Java应用程序时指定相应的命令行参数来设置。

JVM垃圾回收的柱石 - G1GC

G1是一种设计用于多核和大容量内存系统的垃圾回收器,它的主要目标是提供稳定的低延迟和高吞吐量,在尽可能短的时间内回收垃圾。

G1算法原理

G1算法将堆内存按照Region(固定大小的内存块)进行划分,然后通过几个阶段来回收垃圾:

  1. 初始标记阶段:在此阶段中,垃圾回收器初步扫描GC Roots(如静态变量、本地变量、活动线程的堆栈中的引用)和部分可达对象,用于确定哪些Region中有垃圾需要回收。此阶段暂停应用程序。

  2. 并发标记阶段:在此阶段中,垃圾回收器并发进行扫描和标记所有可达对象,同时应用程序在运行。在此过程中,垃圾回收器记录Region的垃圾情况,以便后续的回收。

  3. 最终标记阶段:在此阶段中,垃圾回收器再次暂停应用程序,进一步标记所有垃圾对象,并清除被标记为垃圾的Region。

  4. 重置阶段:在此阶段中,垃圾回收器对未清除的Region进行清除,并将这些Region添加到空闲列表中。此阶段需要暂停应用程序。

G1算法的特点是将垃圾回收过程拆分为多个阶段,并且在整个过程中都与应用程序并发运行,以便减少应用程序的停顿时间。此外,G1还能够根据下一次垃圾回收分配时间,智能选择回收目标和回收的内存区域,以最小化回收垃圾的时间和影响。

G1算法的流程

下面是G1算法执行的大体流程:

graph LR;
    A[初始化GC] --> B[初始标记]
    B --> C[并发标记]
    C --> D[最终标记]
    D --> E[重置]

注:箭头的方向从上到下,表示流程的先后顺序。

G1算法的重要参数

以下是一些关键的G1算法参数和示例代码:

  1. -XX:MaxGCPauseMillis:指定最大GC停顿时间,G1会尽可能满足这个要求。默认是200ms。

    1
    
    -XX:MaxGCPauseMillis=100
    
  2. -XX:G1HeapRegionSize:指定Region的大小。默认为堆大小的1/2000。可以根据情况进行调整。

    1
    
    -XX:G1HeapRegionSize=2m
    
  3. -XX:G1NewSizePercent:指定G1的新生代大小占比。默认为5%。

    1
    
    -XX:G1NewSizePercent=10
    
  4. -XX:G1MaxNewSizePercent:指定G1的最大新生代大小占比。默认为60%。

    1
    
    -XX:G1MaxNewSizePercent=70
    
  5. -XX:MaxGCPauseMillis:指定最大GC停顿时间。默认为200ms。

    1
    
    -XX:MaxGCPauseMillis=100
    
  6. -XX:G1HeapWastePercent:指定堆浪费的最大百分比。默认为5%。

    1
    
    -XX:G1HeapWastePercent=10
    

以上参数可以通过在启动Java应用程序时指定相应的命令行参数来设置。

对比G1GC和CMS的差异

  • 内存区域: G1GC和CMS的内存区域划分方式不同。G1GC将堆内存划分为大小相等的Region,而CMS则将堆内存划分为两个区域:年轻代和老年代。

  • 执行过程: G1GC采用了一种增量回收的方式,将整个垃圾回收过程分为多个周期,每个周期内仅回收部分区域的垃圾。而CMS算法则是一种基于标记清除的算法,其回收过程可分为四个阶段:初始标记阶段、并发标记阶段、重新标记阶段和并发清除阶段。

  • 低延迟: G1GC算法的一个重要特点是低延迟,它可以根据用户指定的最大停顿时间来调整回收策略,从而尽可能减少应用程序的停顿时间。而CMS算法也具备低延迟的优势,它的并发标记和清理过程不需要停止应用程序,因此可以减少应用程序的停顿时间。

  • 压缩机制: G1GC算法具有自动压缩机制,它可以定期对需要压缩的Region进行压缩,从而减少内存碎片,提高内存利用率。而CMS算法则没有内存压缩机制,因此当出现内存碎片时,可能需要重新分配连续的内存空间,这可能会导致应用程序对内存资源的争夺,从而影响应用程序的性能。

  • 可控性: G1GC算法具有高度的可控性,用户可以通过指定多个参数来控制垃圾回收过程,从而适应不同的性能需求和场景。而CMS算法的可控性相对较低,用户可以指定的参数较少,因此可能需要使用更高级的工具和技术来优化和调整垃圾回收过程。

知识共享许可协议

本作品采用 知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议 进行许可。欢迎转载、使用、重新发布,但务必保留文章署名 TinyZ Zzh (包含链接: https://tinyzzh.github.io ),不得用于商业目的,基于本文修改后的作品务必以相同的许可发布。 如有任何疑问,请 与我联系 (tinyzzh815@gmail.com)

TinyZ Zzh

TinyZ Zzh

专注于高并发服务器、网络游戏相关(Java、PHP、Unity3D、Unreal Engine等)技术,热爱游戏事业, 正在努力实现自我价值当中。

评论

  点击开始评论...