06_G1调优配置

本章主要介绍,如果G1默认的一些配置无法满足你的需求,要如何进一步调优。

G1的一般建议

一般建议是使用G1并保持默认设置,如有需要,可以通过使用 -Xmx 来设置最大的Java堆大小,同时也可以通过 -XX:MaxGCPauseMillis来指定不同的暂停时间目标。

G1的默认配置与其他收集器的平衡有所不同。G1在默认配置中的目标既不是追求最大吞吐量,也不是追求最低延迟,而是提供相对较小、统一的暂停时间以获得高吞吐量。然而,G1在堆空间中逐步回收空间和暂停时间控制会给应用线程和空间回收效率带来一些开销。

如果您更看重高吞吐量,则可以通过使用 -XX:MaxGCPauseMillis 放宽暂停时间目标或提供更大的堆。如果延迟是主要考虑因素,则可以修改暂停时间目标。应尽量避免使用类似 -Xmn、-XX:NewRatio 等选项限制年轻代大小,因为年轻代大小是G1控制暂停时间的主要手段。将年轻代大小设置为一个固定值会覆盖并实际上禁用了暂停时间控制。

从其他收集器转向 G1

通常情况下,从其他收集器(尤其是并发标记清除收集器)切换到G1时,首先应删除所有影响垃圾收集的选项,只通过 -Xmx 以及可选的 -Xms 来设置暂停时间目标和总体堆大小。

许多对其他收集器有效的选项在G1中要么根本不起作用,要么甚至会降低吞吐量和满足暂停时间目标的可能性。一个例子就是设置年轻代大小,这样完全阻止了G1调整年轻代大小来满足暂停时间目标。

改善 G1的性能表现

G1旨在在无需指定额外选项的情况下提供良好的整体性能。然而,在某些情况下,默认的启发式算法或其配置可能会导致性能不佳。本节提供了一些诊断和改进这些情况的指南。本指南仅描述了针对给定应用程序,在给定度量标准下,G1提供了哪些可能性来改进垃圾收集器的性能。从案例出发,应用级别的优化可能比尝试调整虚拟机以获得更好性能更为有效,例如通过完全避免一些长生命周期对象所带来的一些问题情况。

为了诊断目的,G1提供了全面的日志记录。一个很好的起点是使用 -Xlog:gc*=debug 选项,然后根据需要细化输出内容。日志提供了关于垃圾收集活动在暂停期间和暂停期间之外的详细概述。其中包括收集类型以及在暂停期间特定阶段所花费的时间。

接下来的小节将探讨一些常见性能问题。

观察FGC

Full GC 通常会耗费大量时间。由于老年代堆内存占用过高而引起的Full GC,在日志中可以通过找到“Pause Full (G1 Compaction Pause)”这些词来检测。而Full GC通常都是由于垃圾回收遭遇了疏散失败(Evacuation Failure)标签表示的先前事件导致。

Full GC发生的原因是因为应用程序分配了太多无法迅速回收的对象。通常情况下,并发标记无法及时完成以启动空间回收阶段。频繁分配大对象可能加剧出现Full GC的概率。由于G1中这些对象的分配方式,它们可能会占用比预期更多的内存。

目标应该是确保并发标记能够按时完成。这可以通过减少老年代中的分配速率,或者给并发标记更多时间来实现。

G1提供了一些选项来更好地处理这种情况:

  • - 可以使用gc+heap=info日志记录来确定Java堆上被巨型对象占用的区域数量。在“Humongous regions:X->Y”这一行中,Y表示被巨型对象占用的区域数量。如果与老年代区域数量相比,这个数字较高,则最佳选项是尝试减少这些对象的数量。可以通过增加区域大小来实现,使用 -XX:G1HeapRegionSize 选项设定区域大小。当前所选的堆区域大小将在日志开头打印出来。
  • - 增加Java堆的大小。通常会增加标记过程完成所需时间。
  • - 通过显式设置 -XX:ConcGCThreads 来增加并发标记线程数。
  • - 强制G1提早开始标记阶段。G1根据先前应用程序行为自动确定初始堆占用百分比(IHOP)阈值。如果应用程序行为发生变化,这些预测可能有误。有两种选择:增加自适应IHOP计算中使用的缓冲区以降低开始空间回收的目标占用率,即修改 -XX:G1ReservePercent;或者通过手动设置 -XX:-G1UseAdaptiveIHOP 和 -XX:InitiatingHeapOccupancyPercent 来禁用IHOP自适应计算。

Full GC除了分配失效之外还有其他原因,通常表明应用程序或某些外部工具导致进行了完整堆收集。如果造成原因是System.gc(),且无法修改应用程序源代码,则可以通过使用 -XX:+ExplicitGCInvokesConcurrent 来缓解Full GC带来的影响,或者通过设置 -XX:+DisableExplicitGC 让虚拟机完全忽略它们;外部工具可能仍然会强制进行Full GC,只能通过不再请求它们来移除这些影响。

巨大对象的碎片

完整的垃圾回收(Full GC)有可能在Java堆内存耗尽之前发生,因为需要找到一组连续的区域。在这种情况下,可以考虑增加堆区域大小,通过使用选项 -XX:G1HeapRegionSize 来减少巨型对象的数量,或者增加堆的大小。在极端情况下,即使可用内存表明有足够的内存空间,G1可能无法为对象分配到足够的连续空间。如果这种情况发生,那么在Full GC无法回收足够的连续空间时会导致虚拟机退出。因此,在这种情况下,除了减少如前所述巨型对象分配的数量或增加堆之外别无选择。

为延迟调优

这部分讨论了改善G1行为的提示,以解决常见的延迟问题,即暂停时间过长的情况。

非常规系统或实时使用

对于每次垃圾回收暂停,gc+cpu=info日志输出中都包含一行,其中包括来自操作系统的信息,详细说明了在暂停期间花费的时间。例如,输出中的一行可能是:User=0.19s Sys=0.00s Real=0.01s。

用户时间是在虚拟机代码中花费的时间,系统时间是在操作系统中花费的时间,而实际时间则是在暂停期间经过的绝对时间量。如果系统时间相对较高,则大多数情况下环境是造成延迟的原因。

导致系统时间过高的常见已知问题包括:

  • - 虚拟机分配或返还操作系统内存可能会导致不必要的延迟。通过使用选项 -Xms 和 -Xmx 将最小堆大小和最大堆大小设置为相同值,并使用 -XX:+AlwaysPreTouch 预分配所有内存,将这一工作移到虚拟机启动阶段以避免这些延迟。
  • - 特别是在Linux环境下,透明大页(THP)功能将小页面合并为大页面,往往会使随机进程停滞,而不仅仅只是在暂停期间。由于虚拟机分配和维护了大量内存,因此出现虚拟机长时间停滞的风险比通常更高。请参阅您操作系统的文档以了解如何禁用透明大页功能。
  • - 由于某些后台任务不时占用写入日志所用硬盘的所有I/O带宽,日志输出可能会暂时停顿一段时间。考虑使用独立硬盘或其他存储设备来存储日志文件,例如基于内存的文件系统,从而避免这种情况。

另一个需要注意的情况是实际时间远远大于其他两者之和,这可能表明虚拟机未能获得足够CPU时间,在可能过载的计算机上发生了长时间停滞。

引用对象处理花费的时间太长

在“引用处理”阶段会显示关于引用对象处理时间的信息。在引用处理阶段,G1根据特定类型的引用对象的需求更新引用对象的引用。默认情况下,G1尝试使用以下启发式方法并行化引用处理的子阶段:对于每个 -XX:ReferencesPerThread 个引用对象,启动一个线程,并受 -XX:ParallelGCThreads 指定线程数的限制。可以通过将 -XX:ReferencesPerThread 设置为 0 来禁用此启发式方法,默认情况下使用所有可用线程,或通过 -XX:-ParallelRefProcEnabled 完全禁用并行化。

年轻代收集耗费太多时间

年轻代的普通收集以及一般情况下任何年轻代收集的时间大致与年轻代的大小成正比,或者更具体地说,与需要被复制的收集集合中的存活对象数量成正比。如果疏散集合阶段花费的时间过长,特别是对象复制子阶段,则可以通过减小 -XX:G1NewSizePercent 来解决。这会减小年轻代的最小大小,有望缩短暂停时间。

另一个关于年轻代大小的问题可能出现在应用程序性能以及尤其是在收集后存活对象数量突然改变时。这可能导致垃圾回收暂停时间出现波动。通过使用 -XX:G1MaxNewSizePercent 减小最大年轻代大小可能会有所帮助。这样可以限制年轻代的最大大小,从而减少暂停期间需要处理的对象数量。

混合收集花费的时间太长

混合年轻代收集用于回收老年代的空间。混合收集的收集集合包含年轻代和老年代区域。您可以通过启用 gc+ergo+cset=debug 日志输出来获取有关疏散年轻代或老年代区域对暂停时间贡献的信息。寻找以下日志消息:

Added young regions to CSet.[...] predicted eden time:4.86ms,predicted base time:9.98ms,target pause time:200.00ms,[...]

Eden 时间和 base 时间一起给出了预测的年轻代区域时间,即 G1 预计疏散年轻代所需的时间。

预测旧区域时间的日志消息如下所示:

Finish choosing collection set old regions.[...] predicted initial time:147.70ms,predicted optional time:15.45ms,[...]

在这里,预测初始时间表示预测的旧区域时间,即 G1 预计疏散最小集合的老年代区域所需的时间。

如果预测的年轻代区域时间太长,请参阅“只有年轻代收集在年轻代阶段花费太长时间”部分进行调整。否则,为了减少老年代区域对暂停时间的贡献,G1 提供了三个选项:

  • 通过增加 -XX:G1MixedGCCountTarget 来将老年代区域回收分布到更多垃圾回收中。
  • 通过使用 -XX:G1MixedGCLiveThresholdPercent 将需要大量时间来回收的区域排除在候选回收集合之外,以避免将它们放入候选回收集合。在许多情况下,占用率高的区域需要大量时间来进行回收。
  • 提早停止老年代空间回收,这样 G1 将不会回收那么多占用率高的区域。在这种情况下,增加 -XX:G1HeapWastePercent。

请注意,最后两个选项会减少候选回收集合中可进行当前空间回收阶段空间回收数量。这可能意味着 G1 可能无法为持续操作回收足够老年代空间。但是,稍后的空间回收阶段可能会进行垃圾回首处理这些空间。

连续出现垃圾回收

G1默认的MMU设置允许连续进行垃圾回收。-XX:GCPauseIntervalMillis 的默认值略高于 -XX:MaxGCPauseMillis。如果观察到连续进行垃圾回收导致应用无法进展,可以增加 -XX:GCPauseIntervalMillis 的值至一个可接受的水平。这样,G1 将尝试减少垃圾回收的频率。

高合并堆根和扫描堆根时间

减少这两个阶段的一种方法是通过调整组合记忆集中记忆集条目的数量来减少。使用 -XX:G1HeapRegionSize 选项调整堆区域的大小可以减少跨区域引用大小的记忆集。更大的区域往往具有较少的跨区域引用,因此在处理它们时所花费的工作量减少,尽管与此同时,更大的区域可能意味着每个区域需要疏散更多存活对象,从而增加其他阶段的时间。

如果垃圾回收过程中有相当多的时间(即超过60%)花费在这两个阶段上,一个选择是通过减小 -XX:GCCardSizeInBytes 选项的值来降低记忆集条目的粒度:更细粒度会减少查找引用所需的工作量,但会增加一些额外内存消耗。

在应用程序分配大对象时,结合出现无端高 Scan Heap Roots 时间可能是由于一种优化引起,该优化尝试通过批量处理来减少并发记忆集更新工作。如果此类批处理是在垃圾回收之前创建的应用程序执行,则可能对 Merge Heap Roots 时间产生负面影响。使用 -XX:-ReduceInitialCardMarks 可以禁用此优化,从而潜在避免出现这种情况。

为吞吐量调优

G1的默认策略试图在吞吐量和延迟之间取得平衡;然而,在某些情况下,更高的吞吐量是可取的。除了按照前面部分所描述的减少总暂停时间之外,还可以减少暂停的频率。主要思路是使用 -XX:MaxGCPauseMillis 增加最大暂停时间。代际大小的启发式方式将自动调整年轻代的大小,这直接决定了暂停的频率。如果这不会产生预期行为,尤其是在空间回收阶段,可以使用 -XX:G1NewSizePercent 来增加最小年轻代大小来强制 G1 这样做。

在某些情况下,-XX:G1MaxNewSizePercent,即允许的年轻代最大大小,可能会通过限制年轻代大小来限制吞吐量。可以通过查看gc+heap=info日志记录中区域汇总输出来进行诊断。在这种情况下,Eden 区域和 Survivor 区域的合并百分比接近于总区域数的 -XX:G1MaxNewSizePercent 百分比。此时可以考虑增加 -XX:G1MaxNewSizePercent。

另一个提高吞吐量的选择是减少并发工作量。特别是,并发记忆集更新通常需要大量 CPU 资源。可以使用 -XX:G1RSetUpdatingPauseTimePercent 选项将工作从并发操作转移到垃圾回收暂停中。

增加此值可能会减少同时调度给应用程序进行细化工作,反之亦然;减少此值可能会增加同时与应用程序进行细化工作的量。

启用 gc+phases=debug 日志记录时,在 Merge Heap Roots 阶段的 Log Buffers 部分跟踪垃圾回收暂停中的细化工作。

通过使用 -XX:+UseLargePages 启用大页功能也可能提高吞吐量。请参考操作系统文档以了解如何设置大页。

您可以通过禁用堆调整工作来尽量减少它;将选项 -Xms 和 -Xmx 设置为相同值。此外,您还可以使用 -XX:+AlwaysPreTouch 将操作系统工作移到虚拟内存上以缩短虚拟机启动时间。这些措施特别有助于使暂停时间更加稳定。

为堆大小调优

与其他收集器一样,G1旨在调整堆大小,使得垃圾回收所花费的时间低于由 -XX:GCTimeRatio 选项确定的比率。调整此选项以使G1满足您的需求。

可调的默认值

本节介绍本主题中引入的默认值和有关命令行选项的一些描述和附加信息。

Option and Default ValueDescription

-XX:+ReduceInitialCardMarks

This batches together concurrent remembered set update (refinement) work for initial object allocations.

-XX:+ParallelRefProcEnabled

-XX:ReferencesPerThread=1000

-XX:ReferencesPerThread determines the degree of parallelization: for every N Reference Objects one thread will participate in the sub-phases of Reference Processing, limited by -XX:ParallelGCThreads. A value of 0 indicates that the maximum number of threads as indicated by the value of -XX:ParallelGCThreads will always be used. 

This determines whether processing of java.lang.Ref.* instances should be done in parallel by multiple threads.

-XX:G1RSetUpdatingPauseTimePercent=10 

The concurrent remembered set update (refinement) work can be controlled with this option. Refinement tries to schedule work concurrently so that at most -XX:G1RSetUpdatingPauseTimePercent percent of the maximum pause time goal is spent in the garbage collection pause in the Update RS phase, processing remaining work.

-XX:G1SummarizeRSetStatsPeriod=0 

This is the period in a number of GCs that G1 generates remembered set summary reports. Set this to zero to disable. Generating remembered set summary reports is a costly operation, so it should be used only if necessary, and with a reasonably high value. Use gc+remset=trace to print anything.

-XX:GCTimeRatio=12 

This is the divisor for the target ratio of time that should be spent in garbage collection as opposed to the application. The actual formula for determining the target fraction of time that can be spent in garbage collection before increasing the heap is 1 / (1 + GCTimeRatio). This default value results in a target with about 8% of the time to be spent in garbage collection.

-XX:G1PeriodicGCInterval=0

The interval in ms to check whether G1 should trigger a periodic garbage collection. Set to zero to disable.

-XX:+G1PeriodicGCInvokesConcurrent

If set, periodic garbage collections trigger a concurrent marking or continue the existing collection cycle, otherwise trigger a Full GC.

-XX:G1PeriodicGCSystemLoadThreshold=0.0Threshold for the current system load as returned by the hosts getloadavg() call to determine whether a periodic garbage collection should be triggered. A current system load higher than this value prevents periodic garbage collections. A value of zero indicates that this threshold check is disabled.

注意: < ergo > 意味着实际值是根据环境的人机工程学确定的。 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/8641.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

MySQL数据库失效:潜在场景、影响与应对策略

在当今数字化时代&#xff0c;数据库作为数据存储和管理的核心组件&#xff0c;其稳定性和可靠性直接影响着业务的连续性和用户体验。MySQL&#xff0c;作为最受欢迎的关系型数据库管理系统之一&#xff0c;广泛应用于互联网、金融、教育等多个行业。然而&#xff0c;即便是这样…

NTP 协议获取网络时间

从github 中找到的一份代码进行的修改 板卡是0区,手动加了8个时区 #include <iostream> #include <netdb.h> #include <netinet/in.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <sys/socket.h> #inclu…

Hikyuu-PF-银行股轮动交易策略实现

今天&#xff0c;带来的是“如何使用 Hikyuu 中的投资组合来实现银行股轮动交易策略”。 这个策略的逻辑很简单&#xff1a;持续持有两支市净率最低银行股&#xff0c;然后每月换仓 定义回测周期与回测标的 同样&#xff0c;首先定义回测周期&#xff1a; # 定义回测日期 …

撰写一份详尽的数据治理实施方案

对于拥有15年经验的资深数据治理工程师而言,是一个复杂而细致的任务,应当涵盖策略规划、组织架构调整、技术选型、流程设计、合规性考量、监控与评估等多个维度。本文概述一个高层次的数据治理实施方案框架,并简要说明每个部分的关键内容。如需深入细节,您可以根据这个框架…

了解内存函数

✨✨欢迎&#x1f44d;&#x1f44d;点赞☕️☕️收藏✍✍评论 个人主页&#xff1a;秋邱博客 所属栏目&#xff1a;C语言 前言 内存函数不止malloc、calloc、realloc、free还有memcpy、memmove、memset、memcmp。前四个的头文件是<stdlib.h>,后四个的头文件是<strin…

Ansible----playbook模块之templates模块、tags模块、roles模块

目录 引言 一、templates模块 &#xff08;一&#xff09;关键信息 &#xff08;二&#xff09;实际操作 1.定义主机组 2.设置免密登录 3.分别建立访问目录 4.定义模板文件 5.创建playbook文件 6.执行剧本 7.验证结果 二、tags模块 &#xff08;一&#xff09;创建…

《QT实用小工具·六十一》带动画的三角形指示箭头

1、概述 源码放在文章末尾 该项目实现了一个带动画效果的三角形指示箭头&#xff0c;项目demo演示如下所示&#xff1a; 用法 interestingindicate.h interestingindicate.cpp 放到工程中&#xff0c;直接使用即可。 注意&#xff1a;建议绝对布局&#xff0c;手动指定 wid…

git stash技巧

1.缘由 有时代码写到一半有新bug要修复&#xff0c;这时可以先暂存当前代码&#xff08;使用git stash&#xff09;&#xff0c;修复完bug再回到原先的暂存文件&#xff08;使用git stash pop&#xff09;继续工作。 2.git stash的常用命令&#xff1a; &#xff08;1&#x…

【大数据】containered学习笔记

文章目录 1. Containerd安装1.1 YUM方式安装 【后端&网络&大数据&数据库目录贴】 1. Containerd安装 1.1 YUM方式安装 获取YUM源 获取阿里云YUM源 wget -O /etc/yum.repos.d/docker-ce.repo https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo 查…

华为车BU迈入新阶段,新任CEO对智能车的3个预判

作者 |张马也 编辑 |德新 4月24日&#xff0c;北京车展前夕&#xff0c;华为召开了新一年的智能汽车解决方案新品发布会。 这次发布会&#xff0c;也是华为智能汽车解决方案BU&#xff08;简称「车BU」&#xff09;CEO 靳玉志的公开首秀。 一开场&#xff0c;靳玉志即抛出了…

BACnet转MQTT网关智联楼宇json格式自定义

智能建筑的BACnet协议作为楼宇自动化领域的通用语言&#xff0c;正逐步迈向更广阔的物联网世界。随着云计算和大数据技术的飞速发展&#xff0c;如何将BACnet设备无缝融入云端生态系统&#xff0c;成为众多楼宇管理者关注的焦点。本文将以一个实际案例&#xff0c;揭示BACnet网…

Clion STM32CubeMX 项目

系列文章目录 前言 最后修改 2024 年 4 月 16 日 操作系统&#xff1a;Windows / Linux / macOS 所需工具 STM32CubeMX、GNU ARM 工具链 项目格式&#xff1a; CMake 兼容配置&#xff1a; OpenOCD 运行与调试/嵌入式 GDB 服务器 对于以 STM32 板卡为目标的嵌入式项目&#xf…

分布式与一致性协议之ZAB协议(七)

ZAB协议 ZAB协议:如何处理读写请求 你应该有这样的体会&#xff0c;如果你想了解一个网络服务&#xff0c;执行的第一个功能肯定是写操作&#xff0c;然后才会执行读操作。比如&#xff0c;你要了解ZooKeeper&#xff0c;那么肯定会在zkClient.sh命令行中执行写操作(比如crea…

如何购买阿里云99计划的ECS云服务器?99元购买阿里云2核2G3M服务器教程

阿里云助力中小企业和开发者无忧上云的“99计划”中有两款性价比超高的ECS云服务器&#xff0c;2026年3月31日活动结束前新购和续费价格一样。 其中个人和企业新老用户同享的2核2G3M服务器仅需99元/年&#xff08;续费同价&#xff09;&#xff0c;企业新老用户同学的2核4G5M仅…

Python 框架安全:Django SQL注入漏洞测试.(CVE-2021-35042)

什么是 Django 框架 Django 是一个用 Python 编写的 Web 应用程序框架。它提供了许多工具和库&#xff0c;使得开发 Web 应用程序变得更加容易和高效。Django 遵循了“MTV”&#xff08;模型-模板-视图&#xff09;的设计模式&#xff0c;将应用程序的不同组件分离开来&#x…

Leetcode 637:二叉树的层平均值

给定一个非空二叉树的根节点 root , 以数组的形式返回每一层节点的平均值。与实际答案相差 10-5 以内的答案可以被接受。 思路&#xff1a;其实就是计算每一层的和&#xff0c;再求平均值。 public static List<Double> averageOfLevels(TreeNode root) {List<Doubl…

《从零开始,搭建一个简单的UVM验证平台》实操

最近的工作中需要用UVM平台去仿真软件同事写的C程序&#xff0c;虽然只要用EDA同事已经搭好的UVM平台稍微改改就行&#xff0c;但对于我这种从未接触过UVM甚至都没用过System Verilog的纯FPGA工程师来说还是很有难度的&#xff0c;因为我对这方面一点概念都没有。 基于此&…

[Kubernetes] 安装KubeSphere

选择4核8G&#xff08;master&#xff09;、8核16G&#xff08;node1&#xff09;、8核16G&#xff08;node2&#xff09; 三台机器&#xff0c;按量付费进行实验&#xff0c;CentOS7.9安装Docker安装Kubernetes安装KubeSphere前置环境: nfs和监控安装KubeSphere masternode1no…

整理好了!2024年最常见 100 道 Java基础面试题(三十五)

上一篇地址&#xff1a;整理好了&#xff01;2024年最常见 100 道 Java基础面试题&#xff08;三十四&#xff09;-CSDN博客 六十九、接口是否可以继承接口&#xff1f; 在Java中&#xff0c;接口可以继承其他接口。这种继承关系允许一个接口扩展另一个接口中定义的常量和抽象…

STL——函数对象和谓词

函数对象 概念 重载函数调用操作符()的类&#xff0c;其对象常被称为仿函数 函数对象使用重载的()时&#xff0c;行为类似函数调用&#xff0c;也叫做仿函数 本质上仿函数是一个类&#xff0c;并不是一个函数 函数对象使用 函数对象在使用时&#xff0c;可以像普通函数一样…