垃圾收集器无法清理垃圾,导致频繁进行完整性垃圾回收。

5

我们使用1.7.0_71版本的并行GC。

java -XX:+PrintCommandLineFlags -XX:+PrintGCDetails -version
-XX:InitialHeapSize=258222272 -XX:MaxHeapSize=4131556352 -XX:+PrintCommandLineFlags -XX:+PrintGCDetails -XX:+UseCompressedOops -XX:+UseParallelGC 
java version "1.7.0_71"
Java(TM) SE Runtime Environment (build 1.7.0_71-b14)
Java HotSpot(TM) 64-Bit Server VM (build 24.71-b01, mixed mode)

在较大的负载下,我们的应用程序每隔几分钟就会创建大量垃圾。小的GC每隔几秒钟触发一次,大的GC每2分钟触发一次。分析后,我们发现堆中有180万个大小为173K的char数组对象没有被清除。小的GC无法回收它们。在进行堆转储时,我们在Eclipse MAT的剩余部分中找到了很多对象。MAT直方图显示了许多char数组(它们是渲染的HTML),但是char数组的所有传入引用和合并路径都无法到达GC根,只有完整的GC才能够回收它们而不是小的GC。为什么小的GC无法回收没有引用对象的char数组?请参见所有引用均为不可达。
有一些对请求对象的引用,在设置为空值后已经清除了它们。
修复之前,存在挂起的HttpServletRequest对象的引用。
与该问题相关的所有图片:https://www.dropbox.com/sh/qgsitzb7x27j8kc/AABoQwR1qPwTPiDtO6B0_Pm7a?dl=0 总体堆:
堆直方图视图:
现在的问题是什么?
  1. Do you think this is issue with garbage collector? We upgraded JBoss 7.1.1 to wildfly 8.2.0.Final. No changes in gc strategy and JDK version. Why gc is not able to reclaim memory where it is pointing to unreachable references.

  2. We can decrease XX:NewRatio to 1. However we are no sure this will work as full gc happens frequently

  3. DO you think moving to G1 GC will help ? Will there be decrease in throughput ? What are best options available for G1 GC. Our heap size -Xms : 1024m , -Xmx 2048m. Perm gen 512m We are not seeing memory leaks, no out of memory error.Attaching full gc log outputs

    2015-05-10 19:32:41 IST| 459.939: [Full GC [PSYoungGen: 8123K->0K(680960K)] [ParOldGen: 782136K->359065K(766464K)] 790260K->359065K(1447424K) [PSPermGen: 202932K->202930K(441344K)], 1.0738240 secs] [Times: user=3.37 sys=0.01, real=1.07 secs]
    2015-05-10 19:32:42 IST| 462.306: [GC [PSYoungGen: 672768K->10534K(685056K)] 1031833K->369600K(1451520K), 0.0450800 secs] [Times: user=0.15 sys=0.00, real=0.04 secs]
    2015-05-10 19:32:44 IST| 463.641: [GC [PSYoungGen: 682790K->9093K(685568K)] 1041856K->373085K(1452032K), 0.0570820 secs] [Times: user=0.16 sys=0.00, real=0.06 secs]
    2015-05-10 19:32:45 IST| 464.936: [GC [PSYoungGen: 681349K->9812K(686080K)] 1045341K->377511K(1452544K), 0.0439060 secs] [Times: user=0.12 sys=0.00, real=0.04 secs]
    2015-05-10 19:32:46 IST| 466.283: [GC [PSYoungGen: 683092K->10733K(686080K)] 1050791K->383554K(1452544K), 0.0464700 secs] [Times: user=0.14 sys=0.00, real=0.05 secs]
    2015-05-10 19:32:48 IST| 467.659: [GC [PSYoungGen: 684013K->11283K(685568K)] 1056834K->388651K(1452032K), 0.1381130 secs] [Times: user=0.30 sys=0.00, real=0.14 secs]
    2015-05-10 19:32:50 IST| 469.734: [GC [PSYoungGen: 684051K->9652K(686080K)] 1061419K->393759K(1452544K), 0.0466800 secs] [Times: user=0.13 sys=0.00, real=0.05 secs]
    2015-05-10 19:32:51 IST| 471.087: [GC [PSYoungGen: 682420K->11253K(685568K)] 1066527K->400087K(1452032K), 0.0589180 secs] [Times: user=0.11 sys=0.00, real=0.06 secs]
    2015-05-10 19:32:52 IST| 472.325: [GC [PSYoungGen: 684021K->7957K(686080K)] 1072855K->403018K(1452544K), 0.0436140 secs] [Times: user=0.13 sys=0.00, real=0.04 secs]
    2015-05-10 19:32:54 IST| 473.606: [GC [PSYoungGen: 680725K->9177K(685056K)] 1075786K->406493K(1451520K), 0.0524990 secs] [Times: user=0.13 sys=0.00, real=0.05 secs]
    
    2015-05-10 19:34:34 IST| 573.526: [GC [PSYoungGen: 684217K->10956K(686080K)] 1440629K->771626K(1452544K), 0.0416620 secs] [Times:  user=0.14 sys=0.00, real=0.04 secs]
     2015-05-10 19:34:34 IST| 573.568: [Full GC [PSYoungGen: 10956K->0K(686080K)] [ParOldGen: 760670K->364958K(818688K)] 771626K->364958K(1504768K) [PSPermGen: 203069K->203069K(420864K)], 0.8001740 secs] >[Times: user=2.46 sys=0.01, real=0.80 secs]
    2015-05-10 19:34:36 IST| 575.600: [GC [PSYoungGen: 674304K->10465K(686592K)] 1039262K->375423K(1505280K), 0.0410330 secs] [Times: user=0.13 sys=0.00, real=0.04 secs]
    2015-05-10 19:36:35 IST| 694.277: [GC [PSYoungGen: 684413K->9342K(687104K)] 1490469K->820033K(1505792K), 0.2160320 secs] [Times: user=0.55 sys=0.08, real=0.21 secs]
    2015-05-10 19:36:36 IST| 695.664: [GC [PSYoungGen: 684670K->8323K(687104K)] 1495361K->823380K(1505792K), 0.0454050 secs] [Times: user=0.11 sys=0.00, real=0.05 secs]
    2015-05-10 19:36:37 IST| 695.710: [Full GC [PSYoungGen: 8323K->0K(687104K)] [ParOldGen: 815056K->363295K(838144K)] 823380K->363295K(1525248K) [PSPermGen: 203095K->203095K(401920K)], 0.8133080 secs] [Times: user=2.43 sys=0.01, real=0.81 secs]
    2015-05-10 19:36:38 IST| 697.669: [GC [PSYoungGen: 675328K->10586K(686592K)] 1038623K->373882K(1524736K), 0.0436000 secs] [Times: user=0.13 sys=0.00, real=0.04 secs]
    ...
    ....
    

无法发布超过2个链接。添加第三个链接。这个截图是在有活动引用undertow HttpServletRequest时的情况。修复之前的MAT图片 https://www.dropbox.com/s/oke21sa6clygl1b/Char%20Array%20Incoming%20reference?dl=0 - Srivathsan
I'm sorry, I cannot provide inline images. However, I can provide the translated text as follows:我很抱歉,我无法提供内联图像。 但是,我可以提供以下翻译文本: - jmj
似乎你的应用程序分配了太多对象,因此你的HTML表示通常直接分配在老年代中,而没有经过年轻代->幸存者部分。其中一个解决方案是减少-XX:NewRation并增加-XX:MaxTenuringThreshold。 - qwwdfsad
2个回答

3
为什么当没有引用对象时,小型GC无法恢复它们?
很可能是因为它们在老年代中。小型GC只能处理年轻代中不可达的对象。
这通常发生在对象的寿命超过了由于续期而无法保留在年轻代中的时间。例如,如果涉及到保留结果一段时间的缓存或请求生命周期超过GC间隔*续期阈值-XX:+PrintTenuringDistribution可能会提供有用信息。
首先,您可以尝试通过-XX:MaxGCPauseMillis = ...提供暂停时间目标。ParallelGC可能能够满足它。
如果这没有帮助,您可以重构代码以减少对象寿命或减少分配速率,以使小型GC更不频繁。
请注意,首要的ParallelGC是吞吐量收集器,在CPU周期方面比并发收集器更有效率,但通常无法满足低暂停时间目标。
你认为转向G1 GC会有帮助吗?
如果您关注暂停时间,很可能会有帮助。您也可以尝试CMS。
如果要尝试G1,则应该切换到java 8,其启发式算法随着时间的推移已经得到了改进,并且仍在成熟。
吞吐量会减少吗?
可能会。这取决于是否有多余的CPU容量以及如何定义/测量吞吐量。即使在不太有利的情况下,降低也可能不显着。
G1 GC的最佳选项是什么?
G1应该是自我调整的(超出了用户提供的暂停和吞吐量目标,这也适用于ParallelGC)。因此,只需启用它并查看它是否提供可接受的性能即可。

谢谢。我们无法通过调整垃圾回收(GC)设置来减少垃圾。但是,我们成功修复了应用程序中发生的冗余调用。这减少了产生的垃圾。我必须承认,冗余调用增加了请求处理时间,导致短生命周期对象被提升到旧一代中。 - Srivathsan

1

我们在.NET中遇到了类似的问题。一个引用泄漏到了Gen1,然后变成了Gen2,最终导致RAM累积到30GB+大小。

虽然与JAVA无直接关系,但我们通过构建自定义内存管理器来解决类似的问题。这使我们能够在进程中存储数亿个对象数天,而不需要加载GC。该解决方案非常适用于缓存,并且比外部Redis/memcache快得多。它使用超快速序列化器对对象进行序列化,这样“引用”就会变成“指针”(我们的两个整数的结构体),这样GC不会被扫描1000000000个对象所过载。

看看这个: https://www.youtube.com/watch?v=Dz_7hukyejQ


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接