【问题标题】:GC pauses get really long after several days几天后 GC 暂停变得非常长
【发布时间】:2015-05-08 05:09:27
【问题描述】:

我正在运行一个构建系统。我们曾经使用 CMS 收集器,但我们开始遭受非常长的完整 GC 周期,吞吐量(不进行 GC 的时间)约为 90%。所以我现在决定切换到 G1,假设即使我有更长的整体 GC 时间,暂停也会更短,从而确保更高的可用性。所以这个想法似乎比我预期的更有效,我几乎 3 天没有看到完整的 GC,吞吐量为 97%,整体 GC 性能要好得多。 (所有截图和数据来自GCViewer

直到现在(第 6 天)。今天,系统简直发疯了。使用的旧空间仅略低于 100%。我看到 Full GC 几乎每 2-3 分钟触发一次:

旧空间利用率:

堆大小为 20G(总共 128G RAM)。我目前使用的标志是:

-XX:+UseG1GC
-XX:MaxPermSize=512m
-XX:MaxGCPauseMillis=800
-XX:GCPauseIntervalMillis=8000 
-XX:NewRatio=4
-XX:PermSize=256m
-XX:InitiatingHeapOccupancyPercent=35
-XX:+ParallelRefProcEnabled

加上日志标志。我似乎缺少的是-XX:+ParallelGCThreads=20(我有 32 个处理器),默认应该是 8。我还从 oracle 中读到建议将-XX:+G1NewSizePercent=4 用于 20G 堆,默认应该是 5。

我正在使用 Java HotSpot(TM) 64 位服务器 VM 1.7.0_76,Oracle Corporation

你有什么建议?我有明显的错误吗?要改变什么? 我只给 Java 20G 是不是很贪心?这里的假设是,给它太多堆意味着更长的 GC,因为需要清理的东西更多(农民逻辑)。

PS:申请不是我的。对我来说,它是一个盒子产品。

【问题讨论】:

  • 我认为您的软件中存在一些内存泄漏,这将慢慢消耗可用的堆空间,随着时间的推移,GC 的工作越来越难。因此,不要在 GC 算法或堆设置中搜索解决方案(无论其大小如何,最终都会被填满)。你必须修复你的软件,或者忍受你需要不时重启它的事实。有趣的是,看起来你的堆不会完全填满,导致你的程序崩溃,所以也许我错了。
  • 你应该粘贴一个用-XX:+PrintGCDetails -XX:+PrintGCTimeStamps -XX:+PrintAdaptiveSizePolicy -Xloggc:<logfile>打印的GC日志,这对于理解G1的决定会更有用。如果可以的话,你应该试试 java 8,从那时起,G1GC 发生了很多变化。它的许多启发式方法都得到了改进,并消除了一些瓶颈。 IIRC 在 7 中,G1 可以在某些情况下“将自己画到角落”
  • 我找到了一个解决方案,系统还允许用户在构建过程中执行自定义脚本。经过(很长的)调查,结果发现一个用户一直在执行一个脚本,该脚本没有释放内存,导致堆基线稳步上升,因此每轮释放的 GC 周期越来越少。

标签: java memory-leaks garbage-collection jvm g1gc


【解决方案1】:

你有什么建议?我有明显的错误吗?要改变什么?我只给 Java 20G 是不是很贪心?这里的假设是,给它太多堆意味着更长的 GC,因为需要清理的东西更多(农民逻辑)。

如果它触发了完整的 GC,但您的占用率保持在 20GB 附近,那么 GC 可能根本没有足够的喘息空间来满足大量分配的需求或满足其某些目标(吞吐量、暂停时间),强制使用完整的 GC 作为后备。

因此,您可以尝试增加堆限制或放宽吞吐量目标。

正如我之前在评论中提到的,您还可以尝试升级到 java8 以改进 G1 启发式。

有关“berzerk”行为的更多建议,GC 日志会很有用。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多