1

环境详细信息:操作系统:Linux RedHat Java:JRE 6 Update 21

我正在为我的应用程序使用以下 GC 设置。

-server -d64 -Xms8192m -Xmx8192m -javaagent:lib/instrum.jar -XX\:MaxPermSize=256m -XX\:+UseParNewGC -X\:+ParallelRefProcEnabled -XX\:+UseConcMarkSweepGC -XX\:MaxGCPauseMillis=250 -XX\:+CMSIncrementalMode -XX\:+CMSIncrementalPacing -XX\:+CMSParallelRemarkEnabled -verbose\:gc -Xloggc\:/tmp/my-gc.log -XX\:DisableExplicitGC -XX\:+PrintGCTimeStamps -XX\:+PrintGCDetails -XX\:+UseCompressedOops

有了那里的设置,在应用程序开始时会有一个 Full GC

2.946: [Full GC 2.946: [CMS: 0K->7394K(8111744K), 0.1364080 secs] 38550K->7394K(8360960K), [CMS Perm : 21247K->21216K(21248K)], 0.1365530 secs] [Times: user=0.10 sys=0.04, real=0.14 secs] 

随后是 4-5 次成功的 CMS 收集,但在此之后日志中没有 CMS 的痕迹,只有次要收集上有条目。

379022.293: [GC 379022.293: [ParNew: 228000K->4959K(249216K), 0.0152000 secs] 7067945K->6845720K(8360960K) icms_dc=0 , 0.0153940 secs]

堆不断增长,已达到 7GB。我们必须重新启动应用程序,因为我们无法承受 OOM 或生产系统中的任何故障。

我不明白为什么 CMS 收集器停止清理。欢迎任何线索/建议。提前致谢。

==================================================== =====================================1月23日更新。

感谢大家到现在为止的回复。我已经在测试环境中设置了应用程序并使用以下一组 JVM 选项测试了该应用程序:

选项1

-server -d64 -Xms8192m -Xmx8192m -javaagent\:instrum.jar -XX\:MaxPermSize\=256m -XX\:+UseParNewGC -XX\:+UseConcMarkSweepGC -verbose\:gc -Xloggc\:my-gc.log -XX\:+PrintGCTimeStamps -XX\:+PrintGCDetails

选项 #2

-server -d64 -Xms8192m -Xmx8192m -javaagent\:instrum.jar -XX\:MaxPermSize\=256m -XX\:+UseParNewGC -XX\:+UseConcMarkSweepGC -verbose\:gc -Xloggc\:my-gc.log -XX\:+DisableExplicitGC -XX\:+PrintGCTimeStamps -XX\:+PrintGCDetails

我用两种设置并行运行了 2 天的测试。这些是我的观察:

选项 #1 堆内存稳定,但有 90 个 ConcurrentMarkSweep 集合,JVM 花费了 24 分钟。那太高了。我在 GC 日志中看到以下几行,并且模式每隔一小时继续一次......

318995.941: [GC 318995.941: [ParNew: 230230K->8627K(249216K), 0.0107540 secs] 5687617K->5466913K(8360960K), 0.0109030 secs] [Times: user=0.11 sys=0.00, real=0.01 secs]
319050.363: [GC 319050.363: [ParNew: 230195K->9076K(249216K), 0.0118420 secs] 5688481K->5468316K(8360960K), 0.0120470 secs] [Times: user=0.12 sys=0.01, real=0.01 secs]
319134.118: [GC 319134.118: [ParNew: 230644K->8503K(249216K), 0.0105910 secs] 5689884K->5468704K(8360960K), 0.0107430 secs] [Times: user=0.11 sys=0.00, real=0.01 secs]
319159.250: [Full GC (System) 319159.250: [CMS: 5460200K->5412132K(8111744K), 19.1981050 secs] 5497326K->5412132K(8360960K), [CMS Perm : 72243K->72239K(120136K)], 19.1983210 secs] [Times: user=19.14 sys=0.06, real=19.19 secs]

我没有看到并发标记和扫描日志。这是否意味着 CMS 切换到吞吐量收集器?如果是,为什么?

选项#2:

由于我看到了 Full GC (System) 日志,所以我想到了添加 -XX\:+DisableExplicitGC。但是使用该选项不会发生收集,当前堆大小为 7.5G。我想知道为什么 CMS 正在执行 Full GC 而不是并发收集。

4

4 回答 4

1

这是一个理论...

我怀疑那些 CMS 集合并不完全成功。12477.056 处的事件看起来 CMS 可能已决定由于“预清理”步骤耗时太长而无法正常工作。

如果这导致 CMS 决定关闭,那么我预计它将恢复使用经典的“吞吐量”GC 算法。很有可能它会等到堆满后再运行完整的 GC。简而言之,如果你让它继续它会没问题(模你会时不时地得到大的 GC 暂停。)


我建议您在具有相同堆大小和其他 GC 参数的测试服务器上运行您的应用程序,看看当服务器达到限制时会发生什么。它真的会抛出 OOME 吗?

于 2012-01-10T03:47:06.390 回答
1

CMS 正在为您运行:P

您在 CMS 上使用增量模式(尽管实际上您不应该打扰,因为它可能会惩罚您的吞吐量)

您发布的日志行中的 icms_dc 是一个赠品,在 JVM 中记录此内容的唯一内容是...... CMS 收集器,它说对于 GC 运行,您做了少量与应用程序交织在一起的任期清理。

您的这部分日志与并行新相关(赠送的是堆大小)

379022.293:[GC 379022.293:[ParNew:228000K->4959K(249216K),0.0152000 秒]

这部分是增量CMS(iCMS)

7067945K->6845720K(8360960K) icms_dc=0 , 0.0153940 秒]

我会问,你为什么使用 iCMS,你有很多软/弱/幻影引用(或者你为什么使用 ParallelRefProcEnabled 标志),你是否真的看到内存不足或无法忍受的暂停。

尝试退回到 CompressedOops、ParNewGC 和 CMS,而无需其他任何花哨的东西,看看这是否适合您。

于 2012-01-13T04:23:52.847 回答
0

当您设置最大大小时,它会立即分配该数量的虚拟内存。

当您设置最小尺寸时,它已经分配了最大尺寸。最小大小所做的只是采取最少的步骤来释放内存,直到达到这个最大值。这可能会减少完整 GC 的数量,因为您告诉它最多可以自由使用 8 GB。

您打开了很多选项(其中一些是默认选项)我建议您剥离到最小设置,因为当您打开很多选项时它们可能会有奇怪的交互。

我会从(假设你有 Solaris)开始

-mx8g -javaagent:lib/instrum.jar -XX:MaxPermSize=256m -XX:+UseConcMarkSweepGC -verbose\:gc -Xloggc\:/tmp/my-gc.log -XX:+PrintGCTimeStamps -XX:+PrintGCDetails

这些选项-server是服务器类机器-XX:+UseCompressedOops上的默认值,是最新版本的 Java 上的默认值,-XX:MaxGCPauseMillis=250只是一个提示。

http://www.oracle.com/technetwork/java/javase/tech/vmoptions-jsp-140102.html

于 2012-01-10T08:15:29.707 回答
0

我可以看到初始堆大小 -Xms 为:8192m,最大堆大小为 -Xmx8192m,这可能是 GC 仍在等待开始扫描的原因之一。我建议减少堆大小,然后检查 GC 是否启动。

于 2012-01-10T04:07:34.797 回答