为什么 Java G1 gc 花费这么多时间扫描 RS?

2023-11-21

我目前正在评估 G1 垃圾收集器及其在我们的应用程序中的执行情况。查看 gc-log,我注意到很多集合都有很长的“Scan RS”阶段:

7968.869: [GC pause (mixed), 10.27831700 secs]
   [Parallel Time: 10080.8 ms]
   (...)
      [Scan RS (ms):  4030.4  4034.1  4032.0  4032.0
       Avg: 4032.1, Min: 4030.4, Max: 4034.1, Diff:   3.7]
      [Object Copy (ms):  6038.5  6033.3  6036.7  6037.1
       Avg: 6036.4, Min: 6033.3, Max: 6038.5, Diff:   5.2]
   (...)
    [Eden: 19680M(19680M)->0B(20512M) Survivors: 2688M->2624M Heap:
     75331M(111904M)->51633M(115744M)]
 [Times: user=40.49 sys=0.02, real=10.28 secs] 

所有删除的日志行条目均以个位数毫秒显示运行时间。

我想大部分时间应该花在抄写上吧? Scan RS 花费这么长时间的原因可能是什么?关于如何调整 G1 设置有什么想法吗? JVM 启动于

-Xms40960M -Xmx128G -XX:+UseG1GC -verbose:gc -XX:+PrintGCDetails -Xloggc:gc.log

编辑:哦,我忘了......我正在使用 Java 7u25

Update:我还注意到另外两件奇怪的事情:

16187.740: [GC concurrent-mark-start]
16203.934: [GC pause (young), 2.89871800 secs]
(...)
16218.455: [GC pause (young), 4.61375100 secs]
(...)
16237.441: [GC pause (young), 4.46131800 secs]
(...)
16257.785: [GC pause (young), 4.73922600 secs]
(...)
16275.417: [GC pause (young), 3.87863400 secs]
(...)
16291.505: [GC pause (young), 3.72626400 secs]
(...)
16307.824: [GC pause (young), 3.72921700 secs]
(...)
16325.851: [GC pause (young), 3.91060700 secs]
(...)
16354.600: [GC pause (young), 5.61306000 secs]
(...)
16393.069: [GC pause (young), 17.50453200 secs]
(...)
16414.590: [GC concurrent-mark-end, 226.8497670 sec]

在执行并行运行的同时,并发 GC 运行仍在继续。我不确定这是否是有意的,但对我来说这似乎有点不对。诚然,这是一个极端的例子,但我确实在我的日志中看到了这种行为。

另一件事是我的 JVM 进程增长到了 160g。考虑到 128g 的堆大小,这是一个相当大的开销。这是预期的结果,还是 G1 内存泄漏?关于如何找出答案有什么想法吗?

PS:我不太确定我是否应该为更新提出新问题...如果你们中有人认为这会有所帮助,请告诉我;)

更新2:我猜 G1 确实可能存在内存泄漏:http://printfdebugger.tumblr.com/post/19142660766/how-i-learned-to-love-cms-and-had-my-heart-broken-by-g1由于目前这是一个破坏性的事情,我不会花更多的时间来解决这个问题。 我尚未尝试的事情是配置区域大小(-XX:G1HeapRegionSize)并降低堆占用率(-XX:InitiatingHeapOccupancyPercent)。


让我们来看看。

1 - 第一个线索

看起来您的 GC 已配置为使用 4 个线程(或者您有 4 个 vCPU,但考虑到堆的大小,这不太可能)。对于 128GB 堆来说,这个值相当低,我本来期望更多。

GC 事件似乎以 25 秒以上的间隔发生。但是,您提供的日志摘录并未提及已处理的区域数量。

=> 无论如何,您是否为 G1GC 指定了暂停时间目标(-XX:MaxGCPauseMillis=N) ?

2 - 长扫描 RSet 时间

“Scan RSet”是指 GC 扫描 Remembered Sets 所花费的时间。区域的记住集包含与指向该区域的引用相对应的卡片。此阶段扫描那些卡片,查找指向集合集所有区域的引用。

那么在这里,我们还有一个问题:

=> 在该特定集合期间处理了多少个区域(即 CSet 有多大)

3 - 对象复制时间长

复制时间,顾名思义,是每个工作线程将活动对象从集合集中的区域复制到其他区域所花费的时间。

如此长的复制时间可能表明处理了很多区域,并且您可能需要减少该数量。它还可能建议交换,但考虑到日志末尾的用户/实际值,这种可能性很小。

4 - 现在该怎么办

您应该在 GC 日志中检查已处理的区域数量。将此数字与您的区域大小相关联,并推断出扫描的内存量。

然后,您可以设置较小的暂停时间目标(例如,使用 500 毫秒)-XX:MaxGCPauseMillis=500)。这会

  • 增加 GC 事件的数量,
  • 减少每个 GC 周期释放的内存量
  • 减少 YGC 期间 STW 暂停

希望有帮助!

资料来源:

  • https://blogs.oracle.com/poonam/entry/understanding_g1_gc_logs
  • http://www.oracle.com/webfolder/technetwork/tutorials/obe/java/G1GettingStarted/index.html
  • http://jvm-options.tech.xebia.fr/
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

为什么 Java G1 gc 花费这么多时间扫描 RS? 的相关文章

  • C#:正确使用 Wea​​kReference IsAlive 属性

    正如所解释的here https msdn microsoft com en us library system weakreference isalive v vs 110 aspx if WeakReference s IsAlive返
  • 用于测量 GC 活动的 V8 垃圾收集器回调

    我有一个关于V8的小问题6 7 240GC 行为和AddGCPrologueCallback AddGCEpilogueCallback回调 问题背后的一个小故事 我们使用 V8 引擎启动自定义 JS 代码 为了限制执行时间 我们有一个wa
  • C# 和 Java 中的垃圾收集之间的根本区别是什么?

    最近 我从一位 高级 开发人员 同事那里得到了一些关于 C 垃圾收集器的听起来非常错误的建议 例如 你需要使用析构函数 C 中随处可见 因为垃圾 收藏家不能信赖 C 垃圾收集器不能 就像 Java 垃圾一样 集电极 这对我来说听起来非常可疑
  • Java 堆被无法访问的对象淹没

    我们的 Java EE 应用程序开始出现一些严重问题 具体来说 应用程序在启动后几分钟内就运行了高达 99 的老年代堆 不会抛出 OOM 但实际上 JVM 没有响应 jstat 显示老年代的大小根本没有减少 没有垃圾收集正在进行 并且kil
  • 我用带有垃圾收集器的语言构建了一个解释器。我需要一个用于解释器的垃圾收集器吗?

    这是一个幼稚的问题 但在我迄今为止看到的教程中并没有拼写清楚 如果我在一种高级语言 不是 C C 等 之上构建一个解释器 并且它有一个垃圾收集器 是否有必要为解释器本身制作一个 如果答案是肯定的 那一定是同一类宿主吧 即 如果主机是标记 清
  • 使用套接字时避免垃圾收集

    在我的一个游戏项目中 我尽力避免创建对象 从而阻止垃圾收集器运行 这是一个网络游戏 我主要发送数据的字节数组 但也发送一些其他对象 例如 int 数组 我在分析 Eclipse 中的内存分配时注意到 通过我向套接字写入 读取的方式 在我的程
  • C# 获取分配总数

    有没有办法获得分配总数 注意 分配数量 而不是分配的字节数 它可以是当前线程的 也可以是全局的 以更容易的为准 我想检查特定函数分配了多少个对象 虽然我了解 调试 gt 性能分析器 Alt F2 但我希望能够从程序内部以编程方式执行此操作
  • WinRT 有垃圾收集吗?

    WinRT 有垃圾收集吗 或者它是否像 COM 一样进行引用计数 I found 本文 http www itwriting com blog 4866 a few facts about microsofts new windows ru
  • 为什么访问 PerformanceCounter 会导致第 2 代垃圾回收

    当我从 C 应用程序中访问某些 PerformanceCounters 时 我看到一些奇怪的行为 例如 当我访问 Process Private Bytes 时 似乎我得到了很多第 2 代垃圾收集 对于其他进程计数器来说似乎也是如此 下面的
  • .Net 与 Java 垃圾收集器

    有谁知道 Java 和 Net 垃圾收集器之间的主要区别 网上搜索并没有透露太多信息 这是一个测试中出现的问题 区别在于 CLR Net GC 和 JVM GC 之间 而不是语言本身 两者都可能发生变化 并且其行为规范宽松 允许在不影响程序
  • 流畅的界面是否会显着影响 .NET 应用程序的运行时性能?

    我目前正忙于为现有技术实现一个流畅的接口 这将允许类似于以下代码片段的代码 using var directory Open Directory path to some directory using var file Open File
  • C# 中如何实现引用返回?

    既然 C GC 可以移动内存 那么如何实现引用返回呢 下面的代码会导致 未定义的行为 吗 public struct Record public int Hash public VeryLargeStruct Data public cla
  • Oracle的服务器JRE包含JDK?

    我刚刚下载了适用于 Java SE 7 的 Oracle Server JRE link http www oracle com technetwork java javase downloads server jre7 downloads
  • 运行“git gui”时如何跳过“松散对象”弹出窗口

    当我运行 git gui 时 我会看到一个弹出窗口 上面写着 This repository currently has approximately 1500 loose objects 然后它建议压缩数据库 我之前已经这样做过 它将松散对
  • Java G1 GC 处理引用对象运行缓慢

    我已经在 J ava 上运行了计数器 它24小时工作 每秒点击通过100次左右 白天 GC 处理时间从 20 60 毫秒缓慢上升到 10000 60000 毫秒 然后下降到 20 60 毫秒 这种模式不时地重复 从 GC 日志中我发现 GC
  • JVM内存段分配

    好吧 我有一个关于 JVM 内存段的问题 我知道每个 JVM 都会选择稍微不同地实现这一点 但这是一个总体概念 在所有 JVM 中应该保持相同 一个在运行时不使用虚拟机执行的标准C C 程序在运行时有四个内存段 代码 堆栈 堆 数据 所有这
  • 在这种情况下垃圾收集器会做什么? [复制]

    这个问题在这里已经有答案了 我试图了解 GC 将如何行动的两种情况 1 有两个对象 object1 和 object2 object1 引用了 object2 object2 引用了 object1 现在 这两个对象都没有被使用 GC 可以
  • 如果加载 dylib,垃圾收集工作队列会崩溃

    我们正在将应用程序从 10 6 移植到 10 8 我正在查看我们在应用程序中加载的 dylib 我面临着非常不寻常的崩溃垃圾收集工作队列并附有以下消息 malloc Thread suspend unable to suspend a th
  • JVisualVM/JConsole 中的 System.gc() 与 GC 按钮

    我目前正在测试处理 XML 模式的概念验证原型 并围绕一个非常消耗内存的树自动机外部库 我已经获得了源代码 构建 我想绘制 真实峰值 堆 随着模式大小的增加 不同运行的内存消耗 使用的指标符合我的目的并且不会影响问题 或者至少是它的合理近似
  • 使用带有终结器的 C++/CLI 定义类时 C# 中的内存泄漏

    当我在 C CLI DLL 中实现一个类时 public ref class DummyClass protected DummyClass some dummy code std cout lt lt hello lt lt std en

随机推荐