我有一个使用 CMS 垃圾收集的 Java 应用程序,它每天都会遭受几次“ParNew(提升失败)”完整 GC(参见下面的示例)。我知道当垃圾收集在老一代中找不到足够的(连续的)空间来提升新一代的对象时,就会发生提升失败。此时,它被迫执行昂贵的 stop-the-world 完整 GC。我想避免此类事件。
我已经阅读了几篇提出可能解决方案的文章,但我想在这里澄清/巩固它们:
- -Xmx:增加堆大小,例如。从 2G 到 4G——在老一代中提供更多空间的简单解决方案——在我的经验中似乎工作得相当好
- -XX:NewRatio:增加NewRatio,例如。从 2 到 4,为了增加老年代/减少新生代——给老年代更多的空间——到目前为止我的实验似乎没有太大的影响,如果有的话
- -XX:PromotedPadding:增加为避免升级失败而提供的填充量——但是我找不到任何关于为这个参数提供什么值的建议——有人知道这个值的含义,默认值是什么,或者什么值尝试?
- -XX:CMSInitiatingOccupancyFraction -XX:+UseCMSInitiatingOccupancyOnly: 让 CMS 循环更早开始以避免老年代空间不足——我还没有尝试过这个解决方案——尝试什么值是合理的?什么是默认值?
- 不要在堆上分配非常大的对象:一个非常大的对象可能难以提升,因为它需要在老年代大量连续的可用空间——据我所知,这不适用于我的应用程序
如果相关,这里是我当前的 GC 选项和升级失败事件之前的日志示例。
-Xmx4g -XX:+UseConcMarkSweepGC -XX:NewRatio=1
2014-12-19T09:38:34.304+0100: [GC (Allocation Failure) [ParNew: 1887488K->209664K(1887488K), 0.0685828 secs] 3115998K->1551788K(3984640K), 0.0690028 secs] [Times: user=0.50 sys=0.02, real=0.07 secs]
2014-12-19T09:38:35.962+0100: [GC (Allocation Failure) [ParNew: 1887488K->208840K(1887488K), 0.0827565 secs] 3229612K->1687030K(3984640K), 0.0831611 secs] [Times: user=0.39 sys=0.03, real=0.08 secs]
2014-12-19T09:38:39.975+0100: [GC (Allocation Failure) [ParNew: 1886664K->114108K(1887488K), 0.0442130 secs] 3364854K->1592298K(3984640K), 0.0446680 secs] [Times: user=0.31 sys=0.00, real=0.05 secs]
2014-12-19T09:38:44.818+0100: [GC (Allocation Failure) [ParNew: 1791932K->167245K(1887488K), 0.0588917 secs] 3270122K->1645435K(3984640K), 0.0593308 secs] [Times: user=0.57 sys=0.00, real=0.06 secs]
2014-12-19T09:38:49.239+0100: [GC (Allocation Failure) [ParNew (promotion failed): 1845069K->1819715K(1887488K), 0.4417916 secs][CMS: 1499941K->647982K(2097152K), 2.4203021 secs] 3323259K->647982K(3984640K), [Metaspace: 137778K->137778K(1177600K)], 2.8626552 secs] [Times: user=3.46 sys=0.01, real=2.86 secs]