简短形式:CMS垃圾收集器似乎未能收集不断增加的垃圾;最终,我们的JVM填充了,该应用程序变得无反应。通过外部工具强迫GC(JConsole或 jmap -histo:live)清洁一次。

更新:问题似乎与JConsole的JTOP插件有关;如果我们不运行JConsole或没有JTOP插件运行,则行为消失了。

(技术说明:我们正在运行Sun JDK 1.6.0_07,32位,在Linux 2.6.9框上。升级JDK版本不是真正的选择,除非有不可避免的,主要的原因。而且,我们的系统不是连接到一台可访问的机器上,因此JConsole等的屏幕截图是不可行的。)

我们目前正在运行以下标志的JVM:

-server -Xms3072m -Xmx3072m -XX:NewSize=512m -XX:MaxNewSize=512m 
-XX:+UseConcMarkSweepGC -XX:+UseParNewGC -XX:+CMSParallelRemarkEnabled 
-XX:CMSInitiatingOccupancyFraction=70 
-verbose:gc -XX:+PrintGCDetails -XX:+PrintGCTimeStamps 
-XX:+DisableExplicitGC

在JConsole观察内存图时,有一个完整的GC在我们应用程序寿命的前几个小时内每15分钟左右运行一次。每次完整的GC之后,仍有越来越多的内存正在使用。几个小时后,该系统达到了稳态,其中CMS旧生成中大约有2GB的使用内存。

听起来像是经典的内存泄漏,除了我们使用任何强制迫使全GC的工具(在JConsole中击中“收集垃圾”按钮或运行 jmap -histo:live, 等等),旧的gen突然下降到〜500MB,我们的应用在接下来的几个小时内再次响应(在此期间,相同的模式继续 - 在每个完整的GC之后,越来越多的旧生成已满。)

值得注意的一件事:在JConsole中,报告的并发标记滚GC计数将保持0,直到我们使用JConsole/JMAP/等强制GC。

使用 jmap -histojmap -histo:live 顺序,我能够确定明显未收集的对象包括:

  • 数百万 HashMapS和阵列 HashMap$Entry (以1:1的比例)
  • 数百万 Vectors和对象数组(1:1的比例,与哈希图的数量大致相同)
  • 数百万 HashSet, Hashtable, , 和 com.sun.jmx.remote.util.OrderClassLoaderS,以及一系列 Hashtable$Entry (每个数字的数量大约相同;大约一半的标题和矢量)

下面的GC输出有一些摘录;我对它们的解释似乎是,CMS GC正在中止,而不会失败。我是否以某种方式误解了此输出?有什么会导致的吗?

在正常运行时,CMS GC输出块看起来像这样:

36301.827: [GC [1 CMS-initial-mark: 1856321K(2621330K)] 1879456K(3093312K), 1.7634200 secs] [Times: user=0.17 sys=0.00, real=0.18 secs]
36303.638: [CMS-concurrent-mark-start]
36314.903: [CMS-concurrent-mark: 7.804/11.264 secs] [Times: user=2.13 sys=0.06, real=1.13 secs]
36314.903: [CMS-concurrent-preclean-start]
36314.963: [CMS-concurrent-preclean: 0.037/0.060 secs] [Times: user=0.01 sys=0.00, real=0.01 secs]
36314.963: [CMS-concurrent-abortable-preclean-start]
36315.195: [GC 36315.195: [ParNew: 428092K->40832K(471872K), 1.1705760 secs] 2284414K->1897153K(3093312K), 1.1710560 secs] [Times: user=0.13 sys=0.02, real=0.12 secs]
CMS: abort preclean due to time 36320.059: [CMS-concurrent-abortable-preclean: 0.844/5.095 secs] [Times: user=0.74 sys=0.05, real=0.51 secs]
36320.062: [GC[YG occupancy: 146166 K (471872 K)]36320.062: [Rescan (parallel), 1.54078550 secs]36321.603: [weak refs processing, 0.0042640 secs] [1 CMS-remark: 1856321K(2621440K)] 2002488K(3093312K), 1.5456150 secs] [Times: user=0.18 sys=0.03, real=0.15 secs]
36321.608: [CMS-concurrent-sweep-start]
36324.650: [CMS-concurrent-sweep: 2.686/3.042 secs] [Times: uesr=0.66 sys=0.02, real=0.30 secs]
36324.651: [CMS-concurrent-reset-start]
36324.700: [CMS-concurrent-reset: 0.050/0.050 secs] [Times: user=0.01 sys=0.00, real=0.01 secs]

就是这样;下一行将是下一个Parnew GC。

当我们使用JMAP -HISTO:LIVE强迫GC时,我们得到了:

48004.088: [CMS-concurrent-mark: 8.012/8.647 secs] [Times: user=1.15 sys=0.02, real=0.87 secs]
(concurrent mode interrupted)

其次是〜125行以下形式:(某些生成的methodaccessor,一些生成的序列化构造仪,一些生成的Constructoraccessor等)

[Unloading class sun.reflect.GeneratedMethodAccessor3]

其次是:

: 1911295K->562232K(2621440K), 15.6886180 secs] 2366440K->562232K(3093312K), [CMS Perm: 52729K->51864K(65536K)], 15.6892270 secs] [Times: user=1.55 sys=0.01, real=1.57 secs]

提前致谢!

有帮助吗?

解决方案

com.sun.jmx.remote.util.util.util.orderclassloader在JMX的远程层中使用,并对代码进行快速审查,建议它们是JVM内部远程请求的Unmarshalling Process的一部分而创建的。这些类负载器的寿命将直接与未经许可的事物的寿命直接相关,以至于一旦不再有任何参考,可以释放classloader。

如果在这种情况下,这些实例的存在是您使用jconsole检查JVM中的行动的直接结果,我不会感到惊讶。而且看来他们只是被GC清理,作为正常操作的一部分。

我想JMX实现可能会有一个错误(在相对最新的JVM中似乎不太可能),或者您可能有一些自定义MBEAN或使用一些引起问题的自定义JMX工具。但是最终,我怀疑订单classloader可能是一个红her的,问题在其他地方(损坏的GC或其他泄漏)。

其他提示

技术说明:我们正在运行Sun JDK 1.6.0_07,32位,在Linux 2.6.9框上。除非存在不可避免的主要原因,否则升级JDK版本并不是真正的选择。

几个较新的Java版本已对CMS垃圾收集器进行了更新。值得注意的是6U12,6U14和6U18。

我不是GC东西的专家,但我猜想6U14中的Preclean修复程序 可能 解决您看到的问题。当然,我可以说关于6U18的班级卸载错误的话。就像我说的那样,我不是GC东西的专家。

有修复程序:

  • 6U10 :(影响6U4+)CMS在-XX时永远不会清除参考物:
  • 6U12:CMS:在同步预拆除过程中溢出对象阵列的编码不正确
  • 6U12:CMS:使用并行并发标记时不正确的溢出处理
  • 6U14:CMS:断言失败“ is_cms_thread == thread :: current() - > is_concurrentgc_thread()”
  • 6U14:CMS断言:_concurrent_iteration_safe_limit更新错过
  • 6U14:CMS:参考列表预述期间的溢出处理不正确
  • 6U14:sigsegv或(!is_null(v),使用CMS和COOPS运行时,“ OOP值永远不会为零”)断言
  • 6U14:CMS:CompactibleFreelistspace :: Block_size()中的Livelock。
  • 6U14:使CMS与压缩oops一起使用
  • 6U18:CMS:带有-XX的核心转储:+usecompressedoops
  • 6U18:CMS:与类卸载有关的错误
  • 6U18:CMS:在CMS上的存在下,不安全的减少InitialCardmarks
  • 6U18:[回归] -xx:with -xx:+useconcmarksweepgc导致致命错误
  • 6U20:卡标记可能会推迟太长

除上述所有内容外,6U14还引入了 G1 垃圾收集器,尽管仍在测试中。 G1旨在替换Java 7中的CMS。

G1可以在Java 6U14中使用,并且具有以下命令行开关的新较新:

-XX:+UnlockExperimentalVMOptions -XX:+UseG1GC

我会从更简单的东西开始,例如:

-server -Xms3072m -Xmx3072m -XX:+UseParallelOldGC -verbose:gc -XX:+PrintGCDetails -XX:+PrintGCTimeStamps 

看看这是否满足您的需求。

看来您正在构建对象,将对象指向他们的所有者(A点指向A)。这导致参考计数剩余大于零,因此垃圾收集器无法清理它们。释放周期时,您需要打破它们。将A或B中的参考无效将解决问题。即使在较大的参考中,这也可以看起来像(a-> b-> c-> d-> a)。矢量和对象数组可以由您的哈希图使用。

远程加载程序的主导物可能表明未能清理并关闭对通过JNDI或其他远程访问方法加载的对象的引用。

编辑:我再次看一下你的最后一行。您可能需要增加验证分配。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top