Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/performance/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
在Java CMS GC中避免升级失败_Java_Performance_Garbage Collection_Concurrent Mark Sweep - Fatal编程技术网

在Java CMS GC中避免升级失败

在Java CMS GC中避免升级失败,java,performance,garbage-collection,concurrent-mark-sweep,Java,Performance,Garbage Collection,Concurrent Mark Sweep,我有一个使用CMS垃圾收集的Java应用程序,每天有几次“ParNew(promotion failed)”完整GC(参见下面的示例)。我知道,当垃圾收集在旧一代中找不到足够的(连续的)空间将对象从新一代升级到新一代时,就会发生升级失败。在这一点上,它被迫做一个昂贵的停止全世界GC。我想避免这样的事件 我读过几篇文章,其中提出了可能的解决方案,但我想在这里澄清/整合它们: -Xmx:根据我的经验,增加堆大小,例如从2G增加到4G——这是在老一代中提供更多净空的简单解决方案——似乎效果相当不错 -

我有一个使用CMS垃圾收集的Java应用程序,每天有几次“ParNew(promotion failed)”完整GC(参见下面的示例)。我知道,当垃圾收集在旧一代中找不到足够的(连续的)空间将对象从新一代升级到新一代时,就会发生升级失败。在这一点上,它被迫做一个昂贵的停止全世界GC。我想避免这样的事件

我读过几篇文章,其中提出了可能的解决方案,但我想在这里澄清/整合它们:

  • -Xmx:根据我的经验,增加堆大小,例如从2G增加到4G——这是在老一代中提供更多净空的简单解决方案——似乎效果相当不错
  • -XX:NewRatio:增加NewRatio,例如从2增加到4,以增加老一代/减少新一代--给老一代更多的空间--从我目前的实验来看,似乎没有太大的效果
  • -XX:PromotedPadding:增加为避免升级失败而提供的填充量——但是我找不到任何关于该参数的值的建议——有人知道该值的含义、默认值是什么或者尝试什么值吗
  • -XX:CMSInitiatingOccupancyFraction-XX:+useCminitingoccupancyOnly:让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] 
    

    增加内存是最简单的方法。仍然存在内存最终被碎片化的风险(在极端情况下),我建议您使堆的大小至少为完整GC后使用的内存大小的2.5倍

    CMS中的完整GC非常昂贵,因为它是串行集合而不是并行集合

    另一种方法是使用并行收集,它可以进行碎片整理,而不会退回到串行收集


    网络缓冲区和长字符串是较大的对象。如果它们真的很大,它们会直接进入终身空间,这些似乎是新空间中更大的对象,无法复制到终身空间。

    虽然增加内存确实是最简单和最普遍的解决方案,但在这种情况下,似乎我们有一个特定的问题需要特定的解决方案。查看本例中的GC日志,我会看到如下日志:

    GC (CMS Initial Mark) [1 CMS-initial-mark: 2905552K(3145728K)]
    
    这表明,在CMS开始时,旧的gen已满约92%(使用了3.1Gb中的2.9Gb)。因此JVM决定“占用率”应该在90%左右。这是一个从默认值开始的变化,我认为大约是68%

    显然,我的应用程序的行为方式使JVM认为这是一件好事。但是,应用程序似乎让JVM感到惊讶,因为它突然需要在旧版本中使用更多的空间来升级新版本中的对象

    关于添加GC标志

    -XX:CMSInitiatingOccupancyFraction=50 -XX:+UseCMSInitiatingOccupancyOnly
    
    我们不再看到任何“促销失败”事件。这些标志分别将初始占用率设置为50%,并告诉JVM不要更改这一比例。因此,一旦老一代超过50%,它将启动CMS。这样就避免了等到入住率达到90%左右时再进行“促销失败”的可能性更高