垃圾收集器不能清除垃圾,导致全频繁gc

时间:2015-05-11 20:21:24

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

我们使用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触发,每2分钟触发一次主要gc触发。在分析中,我们发现每个大小为173K的180万个char数组对象留在堆中。 Minor gc无法恢复它们。在获取heapdump时,我们在Eclipe MAT的剩余部分找到了很多对象。 MAT直方图显示了大量的char数组(它们被呈现为html' s),但是所有传入的引用和到char数组的gc root的合并路径都是无法访问的,但只有完整的GC只能恢复它们而不是次要的GC。为什么当没有引用的对象时,次要GC无法恢复它们?附上Eclipse MAT图片。 请注意所有参考文献都无法访问。

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

在修复之前,挂起了对HttpServletRequest对象的引用

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

整体堆 enter image description here

堆直方图视图 enter image description here 现在的问题是

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

  2. 我们可以将XX:NewRatio减少到1.但我们不确定这会因为gc频繁发生而起作用

  3. 您认为转入G1 GC有帮助吗?吞吐量会减少吗?什么是G1 GC的最佳选择。我们的堆大小-Xms:1024m,-Xmx 2048m。 Perm gen 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 个答案:

答案 0 :(得分:2)

  

为什么当没有引用的对象时,次要GC无法恢复它们?

很可能是因为他们是老一代。 Minor GCs只处理年轻一代中无法到达的物体。

这通常发生在物体寿命长于年轻一代因使用期而保留的时间。例如。如果涉及缓存暂停结果或请求生命周期超过GC interval * tenuring threshold的缓存。

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

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

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

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

  

你认为转向G1 GC有帮助吗?

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

如果你想尝试G1,你可能应该切换到java 8,它的启发式方法随着时间的推移已经有了很大的改进,而且它仍然在成熟。

  

吞吐量是否会降低?

可能。这取决于是否有备用CPU容量以及如何定义/测量吞吐量。 即使在不太有利的情况下,减少也许并不重要。

  

G1 GC有哪些最佳选择。

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

答案 1 :(得分:1)

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

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

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