【发布时间】: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