我应该在单个 CPU 系统上使用 SerialGC 还是 G1GC?

Should I use SerialGC or G1GC ona single CPU system?

我有一个限制为 1 CPU 的容器,默认情况下 java 11+(也可能更旧)在这种情况下它给用户 SerialGC。 我应该强制执行线程 GC(如 G1GC)还是将其保留在 SerialGC?

哪一个在单个 CPU 上表现更好? 我一直认为 SerialGC 在这种情况下更好,但我经常看到在某些情况下强制使用 G1GC。

编辑:我要求的是一般案例,因为我们有很多不同的应用程序 运行 使用相同的配置,很难测试每个案例。

根据the documentation

The serial collector uses a single thread to perform all garbage collection work, which makes it relatively efficient because there is no communication overhead between threads.

It's best-suited to single processor machines because it can't take advantage of multiprocessor hardware, although it can be useful on multiprocessors for applications with small data sets (up to approximately 100 MB).

我假设文档中的处理器 = 核心(以及您的问题)。虽然文档说串行收集器不是多核机器的好选择,但它并没有说其他收集器对单核机器不好。

虽然其他收集器确实倾向于使用多线程,但您无法在单核环境中获得这些收集器的全部好处。

那你为什么看到 G1GC 被使用了?也许没有其他原因,因为它是最新的。但是,如果有原因的话,很可能是 G1 提供的更短的 GC 暂停:

If response time is more important than overall throughput and garbage collection pauses must be kept shorter than approximately one second, then select a mostly concurrent collector with -XX:+UseG1GC or -XX:+UseConcMarkSweepGC.

最好的情况是,在这些情况下,他们测量了不同收集器的性能,并选择了提供最佳结果的那个。

还要考虑评论中提到的字符串去重Holger。这是一个特定的内存优化,可能是使用 G1GC 的原因。毕竟如果你只有一个内核,你可能也没有太多的内存可供你使用。

你想优化什么?你是想总是能够极速回答还是想拥有更好的整体表现?在第一种情况下,您应该以更短的 GC 暂停为目标,在第二种情况下,您应该以所有 GC 暂停的总和更低为目标。

您还需要考虑其他因素(即应用程序重启的频率),因此 IMO 最好的方法是数据驱动方法。使用 GC easy or GC viewer 分析每个应用程序的性能并采取相应措施。

请记住,并不总是需要进行 GC 调整,因此如果您不知道要实现什么,您可能会过早地进行优化。

总的来说:

  • 使用Serial GC用于对暂停时间要求不低且运行处​​于资源不足
  • 环境中的应用程序
  • 如果你有更多资源或需要快速回答,请使用G1垃圾收集器(记得测量更改前后的性能)

作为更笼统的评论,不要假设因为您只有一个 core/CPU,所以使任务成为多线程不会有任何好处。根据所涉及的任务(在本例中为 GC),很可能会出现一个线程被阻塞的情况(例如等待 IO 完成),这允许执行任务另一部分的其他线程使用处理器并完成有用的工作。尽管只有一个线程一次能够 运行,但总体性能得到提高。

此线程中未提及的一件重要事情是 G1GC 可以 return 内存(取消提交)返回 OS,因此如果其他应用程序 运行 在服务器上,他们可以利用它。

我在从单个 vCPU 服务器切换到 2 vCPU 服务器时注意到了这一点,因为 java 默认情况下对单个 CPU 使用 SerialGC,对单个 CPU 使用 G1GC multi-CPU(好吧至少它对 JDK 11 有效)