[GC进阶]--调优JVM

英文原文:https://www.oracle.com/technetwork/articles/java/g1gc-1984535.html

垃圾首先垃圾收集器(GC G1)是Java HotSpot虚拟机的低暂停,服务器风格的分代垃圾收集器。G1 GC使用并发和并行阶段来实现其目标暂停时间并保持良好的吞吐量。当G1 GC确定需要进行垃圾收集时,它会首先收集具有最少实时数据的区域(垃圾优先)。

垃圾收集器(GC)是一种内存管理工具。G1 GC通过以下操作实现自动内存管理:

  • 将物体分配给年轻一代并将老年物品推广到老一代。
  • 通过并发(并行)标记阶段在旧一代中查找活动对象。当Java堆总占用率超过默认阈值时,Java HotSpot VM将触发标记阶段。
  • 通过并行复制压缩活动对象来恢复可用内存。

在这里,我们将介绍如何调整和调整G1 GC以进行评估,分析和性能 - 我们假设您对Java垃圾收集有基本的了解。

G1 GC是区域化和分代的垃圾收集器,这意味着Java对象堆(堆)被分成许多大小相等的区域。启动时,Java虚拟机(JVM)设置区域大小。区域大小可以从1 MB到32 MB不等,具体取决于堆大小。目标是不超过2048个地区。伊甸园,幸存者和老一代是这些地区的逻辑集合,并不是连续的。

G1 GC具有尝试满足的暂停时间目标(软实时)。在年轻的系列中,G1 GC调整其年轻一代(伊甸园和幸存者大小)以满足软实时目标。在混合集合期间,G1 GC根据混合垃圾收集的目标数量,堆的每个区域中活动对象的百分比以及总体可接受的堆废弃百分比来调整收集的旧区域的数量。

G1 GC通过将活动对象从一组或多组区域(称为Collection Set(CSet))增量并行复制到不同的新区域来减少堆碎片,以实现压缩。目标是尽可能多地回收堆空间,从包含最可回收空间的区域开始,同时尝试不超过暂停时间目标(垃圾优先)。

G1 GC使用独立的记忆集(RSets)来跟踪对区域的引用。独立的RSet支持并行和独立的区域集合,因为只有区域的RSet必须被扫描以进入该区域,而不是整个堆。G1 GC使用写后屏障来记录对堆的更改并更新RSets。

垃圾收集阶段

除了构成世界末日(STW)年轻和混合垃圾收集的疏散暂停(如下所述),G1 GC还具有并行,并发和多相标记周期。G1 GC使用Snapshot-At-Beginning(SATB)算法,该算法在标记周期开始时获取堆中活动对象集的快照。活动对象集由快照中的活动对象和自标记周期开始以来分配的对象组成。G1 GC标记算法使用预写屏障来记录和标记属于逻辑快照的对象。

年轻的垃圾收集

G1 GC满足来自添加到伊甸园区域集的区域的大多数分配请求。在年轻的垃圾收集过程中,G1 GC从之前的垃圾收集中收集伊甸园区域和幸存区域。来自伊甸园和幸存者区域的活体物体被复制或撤离到一组新的区域。特定对象的目标区域取决于对象的年龄; 已老化的物体充分疏散到老一代地区(即推广); 否则,该物体撤离到幸存者区域,并将被包括在下一个年轻或混合垃圾收集的CSet中。

混合垃圾收集

成功完成并发标记周期后,G1 GC将从执行年轻垃圾收集切换到执行混合垃圾收集。在混合垃圾收集中,G1 GC可选地将一些旧区域添加到将被收集的伊甸园区域和幸存区域中。添加的旧区域的确切数量由稍后将讨论的许多标志控制(参见“ 驯服混合GC ”)。G1 GC收集足够数量的旧区域(通过多个混合垃圾收集)后,G1将恢复执行年轻垃圾收集,直到下一个标记周期完成。

标记周期的阶段

标记周期包括以下阶段:

  • 初始标记阶段:G1 GC在此阶段标记根。这个阶段捎带在正常(STW)年轻垃圾收集上。
  • 根区域扫描阶段:G1 GC扫描初始标记的幸存区域以引用旧代,并标记引用的对象。此阶段与应用程序(而不是STW)同时运行,并且必须在下一个STW年轻垃圾收集开始之前完成。
  • 并发标记阶段:G1 GC在整个堆中查找可到达(实时)对象。此阶段与应用程序同时发生,并且可以被STW年轻垃圾收集中断。
  • 备注阶段:此阶段是STW收集,有助于完成标记周期。G1 GC排出SATB缓冲区,跟踪未访问的活动对象,并执行参考处理。
  • 清理阶段:在最后阶段,G1 GC执行会计和RSet清理的STW操作。在会计期间,G1 GC识别完全自由区域和混合垃圾收集候选者。清理阶段在重置并将空区域返回到空闲列表时部分并发。

重要的默认值

G1 GC是一个自适应垃圾收集器,默认设置使其无需修改即可高效工作。以下是重要选项及其默认值的列表。此列表适用于最新的Java HotSpot VM,版本24.您可以通过在JVM命令行上输入以下选项并更改设置,使G1 GC适应您的应用程序性能需求。

  • -XX:G1HeapRegionSize =true
    
     

    设置G1区域的大小。该值为2的幂,范围从1MB到32MB。目标是根据最小Java堆大小拥有大约2048个区域。

  • -XX:MaxGCPauseMillis = 200
    
     

    设置所需最大暂停时间的目标值。默认值为200毫秒。指定的值不适合您的堆大小。

  • -XX:G1NewSizePercent = 5
    
     

    设置要用作年轻代大小的最小值的堆的百分比。默认值是Java堆的5%。这是一个试验性的旗帜。有关示例,请参阅“ 如何解锁实验性VM标志 ”。此设置将替换该-XX:DefaultMinNewGenPercent设置。此设置在Java HotSpot VM,build 23中不可用。

  • -XX:G1MaxNewSizePercent = 60
    
     

    设置要用作年轻代大小的最大值的堆大小的百分比。默认值为Java堆的60%。这是一个试验性的旗帜。有关示例,请参阅“ 如何解锁实验性VM标志 ”。此设置将替换该-XX:DefaultMaxNewGenPercent设置。此设置在Java HotSpot VM,build 23中不可用。

  • -XX:ParallelGCThreads =true
    
     

    设置STW工作线程的值。将n的值设置为逻辑处理器的数量。值与n逻辑处理器的数量相同,最大值为8。

    如果有超过八个逻辑处理器,则将值设置为逻辑处理器的n大约5/8。这在大多数情况下都有效,除了较大的SPARC系统,其值n可以是逻辑处理器的大约5/16。

  • -XX:ConcGCThreads =ture
    
     

    设置并行标记线程的数量。设置n为并行垃圾收集线程数(ParallelGCThreads)的大约1/4 。

  • -XX:InitiatingHeapOccupancyPercent = 45
    
     

    设置触发标记周期的Java堆占用阈值。默认占用率是整个Java堆的45%。

  • -XX:G1MixedGCLiveThresholdPercent = 65
    
     

    设置要包含在混合垃圾回收周期中的旧区域的占用率阈值。默认入住率为65%。这是一个试验性的旗帜。有关示例,请参阅“ 如何解锁实验性VM标志 ”。此设置将替换该-XX:G1OldCSetRegionLiveThresholdPercent设置。此设置在Java HotSpot VM,build 23中不可用。

  • -XX:G1HeapWastePercent = 10
    
     

    设置您愿意浪费的堆的百分比。当可回收百分比小于堆废弃百分比时,Java HotSpot VM不会启动混合垃圾回收周期。默认值为10%。此设置在Java HotSpot VM,build 23中不可用。

  • -XX:G1MixedGCCountTarget = 8
    
     

    设置标记周期后的混合垃圾收集的目标数量,以收集最多具有G1MixedGCLIveThresholdPercent实时数据的旧区域。默认值为8个混合垃圾收集。混合收集的目标是在此目标数量范围内。此设置在Java HotSpot VM,build 23中不可用。

  • -XX:G1OldCSetRegionThresholdPercent = 10
    
     

    设置混合垃圾回收周期中要收集的旧区域数量的上限。默认值是Java堆的10%。此设置在Java HotSpot VM,build 23中不可用。

  • -XX:G1ReservePercent = 10
    
     

    设置保留空闲的百分比以保持空闲,从而降低空间溢出的风险。默认值为10%。增加或减少百分比时,请确保将总Java堆调整相同的量。此设置在Java HotSpot VM,build 23中不可用。

如何解锁实验性VM标志

要更改实验标志的值,您必须先解锁它们。您可以通过-XX:+UnlockExperimentalVMOptions在任何实验标志之前在命令行上明确设置来完成此操作。例如:

> java -XX:+ UnlockExperimentalVMOptions -XX:G1NewSizePercent = 10 -XX:G1MaxNewSizePercent = 75 G1test.jar

建议

在评估和调整G1 GC时,请记住以下建议:

  • 年轻代大小:避免使用-Xmn选项或任何或其他相关选项明确设置年轻代大小,例如-XX:NewRatio。修复年轻一代的大小会覆盖目标暂停时间目标。
  • 暂停时间目标:当您评估或调整任何垃圾收集时,始终存在延迟与吞吐量的权衡。G1 GC是一个增量垃圾收集器,具有统一的暂停,但在应用程序线程上也有更多的开销。G1 GC的吞吐量目标是90%的应用程序时间和10%的垃圾回收时间。当您将其与Java HotSpot VM的吞吐量收集器进行比较时,目标是99%的应用程序时间和1%的垃圾回收时间。因此,当您评估G1 GC的吞吐量时,请放宽暂停时间目标。设置过于激进的目标表明您愿意承担垃圾收集开销的增加,这会直接影响吞吐量。当您评估G1 GC的延迟时,您可以设置所需的(软)实时目标,G1 GC将尝试满足它。作为副作用,
  • 驯服混合垃圾收集:调整混合垃圾收集时,请尝试以下选项。有关这些选项的信息,请参阅“ 重要默认值 ”:
     
    • -XX:InitiatingHeapOccupancyPercent
      用于更改标记阈值。
    • -XX:G1MixedGCLiveThresholdPercent-XX:G1HeapWastePercent
      当你要更改的混合垃圾收集的决定。
    • -XX:G1MixedGCCountTarget-XX:G1OldCSetRegionThresholdPercent
      当你要调整旧区域的CSet。

溢出和耗尽的日志消息

当您在日志中看到空间溢出/耗尽消息时,G1 GC没有足够的内存用于幸存者或提升的对象,或两者都有。Java堆无法扩展,因为它已经处于最大值。示例消息:

924.897: [GC pause (G1 Evacuation Pause) (mixed) (to-space exhausted), 0.1957310 secs]

要么

924.897: [GC pause (G1 Evacuation Pause) (mixed) (to-space overflow), 0.1957310 secs]

要解决此问题,请尝试以下调整:

增加-XX:G1ReservePercent选项的值(以及相应的总堆)以增加“to-space”的保留内存量。

通过减少来提前开始标记周期-XX:InitiatingHeapOccupancyPercent

您还可以增加-XX:ConcGCThreads选项的值以增加并行标记线程的数量。

有关这些选项的说明,请参阅“ 重要默认值 ”。

令人敬畏的物品和丰富的分配

对于G1 GC,任何超过区域大小一半的对象都被视为“Humongous对象”。这样的对象直接在旧一代中分配到“Humongous regions”。这些Humongous地区是一个连续的区域。StartsHumongous标记连续集的开始并ContinuesHumongous标记集的延续。

在分配任何Humongous区域之前,检查标记阈值,如有必要,启动并发周期。

在完全垃圾收集循环期间,在清理阶段期间,在标记循环结束时释放死Humongous对象。

为了减少复制开销,Humongous对象不包括在任何疏散暂停中。完整的垃圾收集循环将Humongous对象压缩到位。

由于每个单独的StartsHumongous和ContinuesHumongous区域集合仅包含一个巨大的对象,因此未使用对象跨越的大对象的末端和最后区域的末尾之间的空间。对于仅略大于堆区域大小的倍数的对象,此未使用的空间可能导致堆碎片化。

如果您看到由于Humongous分配而启动的背对背并发周期,并且如果此类分配正在分割您的旧代,请增加您的-XX:G1HeapRegionSize以前的Humongous对象不再是Humongous并且将遵循常规分配路径。

结论

G1 GC是一个区域化的,并行并发的增量垃圾收集器,与其他HotSpot GC相比,可提供更可预测的暂停。增量特性使G1 GC可以使用更大的堆,并且仍能提供合理的最坏情况响应时间。G1 GC的自适应特性只需要最大的软实时暂停时间目标以及JVM命令行上Java堆的所需最大和最小大小。

也可以看看

关于作者

Monica Beckwith是Oracle技术人员的主要成员,是Java HotSpot VM的Garbage First Garbage Collector的性能负责人。她在表演和建筑行业工作了10多年。在加入Oracle和Sun Microsystems之前,Monica领导Spansion公司的性能工作.Monica已经与许多基于行业标准的Java基准测试合作,其目标是寻找改进Java HotSpot VM的机会。

猜你喜欢

转载自blog.csdn.net/high2011/article/details/81304590