使用并发标记清除(Concurrent Mark Sweep)垃圾收集器?

7
这个问题基于我从链接 link 的 "Java Garbage Collectors" 部分的了解,看起来 jvm 默认在 Windows 7 上使用 "Parallel GC",我通过 -XX:+PrintCommandLineFlags -version 证实了这一点。本文还说: "并行垃圾回收器使用多个线程执行年轻代垃圾回收。当需要进行大量工作且长时间暂停可接受时应使用此回收器"。 我不确定 Parallel GC 用于老年代收集时使用哪种收集器? 此外,我无法想象出有哪些应用程序可以接受长时间暂停(会导致反应速度较慢)。任何人都希望减少 GC 暂停时间,使应用程序尽可能地响应快。
然后我阅读了 "Concurrent Mark Sweep (CMS) Collector",它收集老年代。
CMS 表示: "它需要低暂停时间,并且可以与垃圾回收共享资源"。 我的问题是,由于其对响应性的重视,难道大多数 Web 应用程序不应该使用 Concurrent Mark Sweep (CMS) 收集器吗? 我相信肯定还有其他因素影响决策,但在阅读此链接后,我觉得应将默认的 GC 类型更改为 Concurrent Mark Sweep (CMS) 收集器。有什么想法/见解吗?
此外,我认为如果我们同时使用 CMS 收集器和并行收集器,其中 CMS 用于老年代,而并行收集器用于年轻代,那么应用程序会更好。
2个回答

8
我不确定Parallel GC在老年代收集时使用哪个收集器?
根据这篇文章,如果使用Parallel GC,则young generation会使用parallel scavenge collector,old generation(也称为tenured generation)会使用parallel mark/sweep collector。所以我的答案是“Parallel GC在老年代收集时使用Parallel GC”。虽然有点循环,但我想这是有道理的。
此外,我无法想象什么应用程序可以接受长时间暂停(将导致响应时间变慢)。任何人都希望GC暂停时间更短,使应用程序尽可能地响应迅速。因为“长暂停”是相对的,它们是否可接受取决于应用程序的类型和用途。需要快速用户交互的应用程序,如游戏,可能需要较低的暂停时间,而长时间运行、几乎没有用户交互(隔夜批处理作业、可以运行数天的处理作业、可能是长时间运行的服务器等)或不需要快速用户交互的应用程序(文字处理软件?但谁会用Java编写文字处理软件?)则对暂停时间要求不那么严格,因此这些应用程序可以接受暂停。此外,暂停不是唯一需要考虑的GC因素,因此即使暂停可接受,也有其他原因选择具有较长暂停时间的GC。我将在下面进一步解释。
我的问题是,难道大多数Web应用程序不应该使用Concurrent Mark Sweep(CMS)收集器,因为它具有响应性吗?
CMS收集器有缺点。在您提到的文章中,有这样一句话:
“通常,并发低暂停收集器不会复制或压缩活动对象。垃圾回收完成后,不会移动活动对象。”
因此,没有堆压缩会导致堆碎片化,这可能对性能有害。 这篇文章指出了另一个缺点(我不确定这篇文章有多可靠,但乍一看似乎相当不错)。
CMS收集器的一个更重要的缺点与老年代堆已满时无法启动相关。一旦老年代已满,CMS便无能为力,必须退回到通常的停止-全球策略(在GC日志中宣布的“并发模式失败”)。然而,CMS最大的缺点与其不会压缩老年代堆有关。因此,它存在堆碎片化和随时间严重操作降级的风险。显然,使用这些设置JVM在负载测试条件下运行良好了近14小时(在生产环境和较低负载下,这种危险的良性期可能会持续更长时间)。然后突然有很长时间的GC暂停,实际上使JVM在剩余时间的一半左右停止。不仅有清理老年代的尝试持续了超过10秒钟,甚至新生代GC暂停也在几秒钟范围内,因为收集器在尝试将对象从新生代提升到老年代时花费了大量时间来搜索老年代中的空间。
此外,如果您拥有Java 7u4或更高版本,则可能还需要考虑闪亮的新G1收集器。它被认为是CMS收集器的替代品。如果将-XX:+UseConcMarkSweepGC参数传递给VM,则实际上是默认模式。但正如上面所述,您可能需要花费一些时间来思考要使用哪个收集器。选择收集器而不考虑您的用例可能不是一个好主意。

Oracle提供的文档在这里: https://docs.oracle.com/javase/7/docs/technotes/guides/vm/G1.html - Gregor

1

我不确定Parallel GC使用哪种收集器来进行老年代空间的收集?

如果您没有指定"-XX:+UseParallelOldGC"标志,JVM将根据机器上可用的核数、操作系统、32/64位等选择单线程或多线程收集器。

我的问题是,大多数Web应用程序不应该使用Concurrent Mark Sweep(CMS)收集器,因为它具有响应性吗?

CMS收集器的问题在于它不会进行老年代内存压缩,导致内存分配性能下降,并最终停止全局FULL GC,就像Parallel GC一样。

如果您的Web应用程序使用较小的堆(4-5GB),且不经常填充(每天1-2次),并且1s /(old gen. GB)的暂停是可以接受的,则Parallel GC是一个很好的选择。

如果您有更大的堆,则CMS是更好的选择,因为它在收集老年代时不会引起长时间的停顿。但是,您仍然应该在非高峰时段安排FULL memory gc,例如每天一次,以进行内存压缩。

我认为最好的做法是同时使用CMS收集器和并行收集器,其中CMS用于老年代,而并行收集器用于年轻代。

这两种收集器无法同时使用:并行GC和CMS。但是两种收集器都可以并行进行年轻代垃圾回收,并且在垃圾回收期间停止应用程序。


你说:“如果你有更大的堆,那么CMS是一个更好的选项”。我认为你这么说的原因是如果我们有更大的堆,堆碎片化就不是一个问题了。是这样吗?但是如果我们有大的堆,即使是并行GC也会较少频繁地进行。所以暂停会存在,但会更少频繁。是这样的吗? - M Sach
是的,使用并行GC会更少地发生垃圾回收,但会在回收时长时间阻塞JVM。CMS是更好的选择,因为在收集旧一代时不会阻塞JVM。 - dcernahoschi

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接