【问题标题】:Garbage collector not able to clear garbage, causes full frequent gc垃圾收集器无法清除垃圾,导致完全频繁的 gc
【发布时间】:2015-05-11 20:21:24
【问题描述】:

我们在 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)

我们看到我们的应用程序在正常负载下每隔几分钟就会产生大量垃圾。 Minor gc 每几秒触发一次,major gc 每两分钟触发一次。经过分析,我们发现有 180 万个大小为 173K 的 char 数组对象留在堆中。 Minor gc 无法恢复它们。在进行 heapdump 时,我们在 Ecipe MAT 的剩余部分中发现了很多对象。 MAT 直方图显示了许多 char 数组(它们被渲染为 html),但是所有传入的引用和对 char 数组的 gc root 的合并路径都无法访问,但只有完整的 GC 只能恢复它们而不是次要的 GC。为什么没有引用对象时,次要 GC 无法恢复它们?附上 Eclipse MAT 图片。 请查看所有引用都无法访问。

有一些对请求对象的引用,通过设置空值来清除它们。

在修复之前,存在对 HttpServletRequest 对象的悬挂引用

与该问题相关的所有图像: https://www.dropbox.com/sh/qgsitzb7x27j8kc/AABoQwR1qPwTPiDtO6B0_Pm7a?dl=0

总堆

堆直方图视图 现在的问题是

  1. 您认为这是垃圾收集器的问题吗?我们将 JBoss 7.1.1 升级到 Wildfly 8.2.0.Final。 gc 策略和 JDK 版本没有变化。为什么 gc 无法回收指向无法访问的引用的内存。

  2. 我们可以将 XX:NewRatio 降低到 1。但是我们不确定这是否会起作用,因为 full gc 经常发生

  3. 您认为迁移到 G1 GC 会有所帮助吗?吞吐量会下降吗? G1 GC 的最佳选择是什么。我们的堆大小 -Xms : 1024m , -Xmx 2048m。烫发 512m 我们没有看到内存泄漏,也没有内存不足错误。附加完整的 gc 日志输出

    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图片dropbox.com/s/oke21sa6clygl1b/…
  • 请将它们作为内嵌图片发布
  • 似乎您的应用分配了太多对象,因此您的 html 表示通常直接在老年代分配,没有年轻->生存部分。解决方案之一是减少 -XX:NewRation 并增加 -XX:MaxTenuringThreshold

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


【解决方案1】:

为什么在没有引用对象的情况下,minor GC 无法恢复它们?

很可能是因为它们属于老一代。 Minor GC 只处理年轻代中无法访问的对象。

这通常发生在对象的寿命长于其在年轻代中的寿命时。例如。如果涉及到缓存会保留结果一段时间或请求生命周期超过 GC interval * tenuring threshold 的生命周期。

-XX:+PrintTenuringDistribution 可能会提供信息。

首先,您可以尝试通过-XX:MaxGCPauseMillis=... 简单地提供暂停时间目标。 ParallelGC 说不定能满足。

如果这对您没有帮助,您可以重构代码以缩短对象生命周期或降低分配率以降低次要 GC 的频率。

请注意,最重要的 ParallelGC 是一个吞吐量收集器,就 CPU 周期而言,它比并发收集器更有效,但它通常无法满足那些低暂停时间目标。

您认为迁移到 G1 GC 会有所帮助吗?

如果您担心暂停时间,很有可能。您可能还想尝试 CMS。

如果您想尝试 G1,您可能应该切换到 java 8,随着时间的推移,它的启发式算法已经有了很大的改进,并且还在不断成熟。

吞吐量会下降吗?

可能。这取决于是否有空闲的 CPU 容量以及您如何定义/测量吞吐量。 即使在不太有利的情况下,减少也可能不会显着。

G1 GC 的最佳选择是什么。

G1 应该进行自我调整(超出用户提供的暂停和吞吐量目标,这些目标也适用于 ParallelGC)。所以只需启用它,看看它是否提供了可接受的性能。

【讨论】:

  • 谢谢。我们无法通过调整 gc 设置来减少垃圾。然而,我们设法修复了在我们的应用程序中发生的冗余调用。这减少了创建的垃圾。我必须同意冗余调用增加了请求处理时间,导致短期对象被提升到老年代。
【解决方案2】:

我们在 >NET 中也发生了类似的问题。参考泄漏到 Gen1 - 并且老化到 Gen 2,最终导致 RAM 累积到 30Gb+ 大小。

虽然与 JAVA 没有直接关系,但我们通过构建一个自定义的内存管理器来解决类似的问题,该内存管理器子分配 byte[]。这使我们能够在不加载 GC 的情况下将数亿个对象存储数天。该解决方案非常适合缓存,并且比进程外 Redis/memcache 快得多。它用超快的序列化器序列化对象,这样“引用”就变成了“指针”(我们的两个整数的结构),这样 GC 就不会因为扫描 1000000000 个对象而过载

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2014-08-26
    • 2023-03-30
    • 2014-01-31
    • 1970-01-01
    • 2011-07-16
    • 2014-09-02
    • 2019-09-19
    • 2018-12-30
    相关资源
    最近更新 更多