Java 当old gen为';空的';

Java 当old gen为';空的';,java,clojure,garbage-collection,jvm,Java,Clojure,Garbage Collection,Jvm,我有一个正在运行的Clojure应用程序,它有大量内存用于大型堆分配,因此它适当地设置了JVM选项: -Xmx13g -XX:+UseConcMarkSweepGC -XX:NewSize=10G -server -XX:+UseParNewGC 这在大多数情况下都有效,并避免了新一代溢出到旧一代的问题(有时仍会进入幸存代,但并不总是如此),但有时我们会看到像图中所示的情况,当新一代已满时,JVM运行CMS/旧一代垃圾回收非常困难。不过,我的理解是,这应该由新一代垃圾收集器来处理 两个问题。

我有一个正在运行的Clojure应用程序,它有大量内存用于大型堆分配,因此它适当地设置了JVM选项:

-Xmx13g -XX:+UseConcMarkSweepGC -XX:NewSize=10G -server -XX:+UseParNewGC
这在大多数情况下都有效,并避免了新一代溢出到旧一代的问题(有时仍会进入幸存代,但并不总是如此),但有时我们会看到像图中所示的情况,当新一代已满时,JVM运行CMS/旧一代垃圾回收非常困难。不过,我的理解是,这应该由新一代垃圾收集器来处理

两个问题。为什么老一代垃圾收集器在老一代几乎是空的而新一代有东西的时候运行?我可以做任何进一步的调整来减少GC暂停/减速,这是不可避免的吗

ETA:在OpenJDK 8上运行

ETA 2:GC日志:

简短回答: CMS花了太多时间扫描近10GB的年轻一代,而它却没有。通过添加以下选项,可以防止CMS收集器不必要地运行:

-XX:+UseCmSinitiatingOccupancy-XX:CmSinitingOccupancyFraction=

其中K是被占用的旧Gen空间的任意分数

长答覆: 关于:

CMS收集器在并发收集周期中暂停应用程序两次。第一个暂停是将可从根(例如,来自应用程序线程堆栈和寄存器的对象引用、静态对象等)和堆中的其他位置(例如,年轻一代)直接访问的对象标记为活动对象。第一次暂停称为初始标记暂停。第二次暂停出现在并发跟踪阶段的末尾,并在CMS收集器完成对对象的跟踪后,查找由于应用程序线程更新对象中的引用而被并发跟踪遗漏的对象。第二次暂停被称为备注暂停

CMS正在进行两次停止世界暂停,每次扫描年轻一代进行标记。查看日志的前三行,您可以看到初始标记在创建新日志之前需要5秒,在创建新日志之后需要0.25秒。这句话在时间上也有类似的减少

<190>1 2015-12-18T08:44:54.194216+00:00 host app web.1 - [GC[YG occupancy: 489826 K (9437184 K)][Rescan (parallel) , 0.2520950 secs][weak refs processing, 0.0000180 secs][scrub string table, 0.0008190 secs] [1 CMS-remark: 64504K(107240K)] 554330K(9544424K), 0.2530410 secs] [Times: user=1.95 sys=0.02, real=0.25 secs]

<190>1 2015-12-18T08:44:49.937257+00:00 host app web.1 - [GC[ParNew:   8418004K->93508K(9437184K), 0.0488580 secs] 8482343K->158013K(9544424K), 0.0489980 secs] [Times: user=0.33 sys=0.00, real=0.05 secs]

<190>1 2015-12-18T08:44:48.651086+00:00 host app web.1 - [GC [1 CMS-initial-mark: 64339K(107240K)] 7800216K(9544424K), 5.0756660 secs] [Times: user=5.08 sys=0.00, real=5.08 secs]
1 2015-12-18T08:44:54.194216+00:00主机应用程序web.1-[GC[YG占用率:489826 K(9437184 K)][Rescan(并行),0.2520950秒][弱引用处理,0.0000180秒][擦洗字符串表,0.0008190秒][1 CMS备注:64504K(107240K)]554330K(95444K),0.2530410秒][次数:用户=1.95 sys 0.02,实际=0.25秒]
1 2015-12-18T08:44:49.937257+00:00主机应用程序web.1-[GC[ParNew:8418004K->93508K(9437184K),0.0488580秒]8482343K->158013K(9544424K),0.0489980秒][次:用户=0.33系统=0.00,实际=0.05秒]
1 2015-12-18T08:44:48.651086+00:00主机应用程序web.1-[GC[1 CMS初始标记:64339K(107240K)]7800216K(9544424K),5.0756660秒][次:用户=5.08系统=0.00,真实=5.08秒]

在每一个CMS周期后,旧的Gen空间几乎不会减少,因此开销肯定不值得。减少CMS循环的频率将是一种可能的解决方案

我看不到oldspace正在进行垃圾收集的迹象。基于看到运行CMS花费了大量CPU时间(请参阅图中的垃圾收集CPU时间图表),您应该启用GC日志记录,并发布一个相当大的样本。您还应该指定正在使用的JVM版本。另外,您的新一代似乎过多了。对不起,我本想包括这个信息:OpenJDK 8。此外,新一代的大小需要如此之大,因为代码最终会为偶尔的短期请求分配7到8 GB的ram用于数据结构。您仍然没有包含GC日志。这似乎解决了问题。将入住率设置为70效果良好。感谢您对cms工作原理的深入了解:我的印象是,与串行gc一样,只有在旧版本中有东西时,它才会运行。