首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Java的串行垃圾收集器的性能比其他垃圾收集器好得多?

Java的串行垃圾收集器的性能比其他垃圾收集器好得多?
EN

Stack Overflow用户
提问于 2012-03-16 22:16:36
回答 5查看 6.2K关注 0票数 11

我正在测试一个用Java编写的API,它可以最小化处理通过网络接收的消息的延迟。为了实现这些目标,我尝试了可用的不同垃圾收集器。

我正在尝试四种不同的技术,它们利用以下标志来控制垃圾收集:

1)串行:-XX:+UseSerialGC

2)并行:-XX:+UseParallelOldGC

3)并发:-XX:+UseConcMarkSweepGC

4)并发/增量:-XX:+UseConcMarkSweepGC -XX:+CMSIncrementalMode -XX:+CMSIncrementalPacing

我在五个小时的过程中运行了每一种技术。我定期使用ManagementFactory.getGarbageCollectorMXBeans()提供的GarbageCollectorMXBean列表来检索收集垃圾所用的总时间。

我的结果?请注意,这里的“延迟”是“我的application+the应用程序接口处理从网络上提取的每条消息所花费的时间”。

串行: 789个GC事件,总计1309ms;平均延迟47.45us,中位延迟8.704 us,最大延迟1197 us

并行: 1715个GC事件,总计122518 ms;平均延迟450.8 us,中位延迟8.448 us,最大延迟8292us

并发:4,629个GC事件,总计116229 ms;平均延迟707.2 us,中位延迟9.216 us,最大延迟9151us

增量: 5066个GC事件,总计200213 ms;平均延迟515.9 us,中位延迟9.472 us,最大延迟14209 us

我发现这些结果是如此不可能,以至于它们近乎荒谬。有人知道为什么我会有这样的结果吗?

哦,顺便说一句,我使用的是Java HotSpot(TM) 64位服务器VM。

EN

回答 5

Stack Overflow用户

发布于 2012-03-16 22:20:29

我正在开发一个Java应用程序,它可以最大化吞吐量和最小化延迟

这有两个问题:

  • 这些通常是相互矛盾的目标,因此您需要确定每个目标相对于另一个目标的重要性(您是否会牺牲10%的延迟来获得20%的吞吐量增益,反之亦然?你是否瞄准了某个特定的延迟目标,超过这个目标,它是否更快都无关紧要?诸如此类的事情)
  • 你还没有给出任何关于这两个

的结果

您所显示的只是在垃圾收集器中花费了多少时间。如果您实际实现了更高的吞吐量,那么您可能希望看到在垃圾收集器中花费更多的时间。或者换一种说法,我可以在代码中进行更改,以使您报告的值非常容易最小化:

代码语言:javascript
复制
// Avoid generating any garbage
Thread.sleep(10000000);

你需要弄清楚对你来说什么才是真正重要的。衡量所有重要的事情,然后找出权衡的地方。因此,首先要做的是重新运行测试并测量延迟和吞吐量。您可能还关心总的CPU使用率(当然,这与GC中的CPU不同),但是当您没有测量您的主要目标时,您的结果不会给您提供特别有用的信息。

票数 18
EN

Stack Overflow用户

发布于 2012-03-16 22:38:51

我一点也不觉得奇怪。

串行垃圾收集的问题是,当它运行时,其他任何东西都不能运行(也就是“停止世界”)。然而,这有一个好的观点:它将花费在垃圾收集上的工作量保持在最低限度。

几乎任何类型的并行或并发垃圾收集都必须做大量的额外工作,以确保对堆的所有修改对于其余代码都是原子的。它必须停止那些依赖于特定更改的事情,然后在足够长的时间内执行该特定更改,而不是仅仅停止一段时间。然后,它让该代码再次开始运行,转到下一个要进行更改的点,停止依赖它的其他代码片段,等等。

另一点(虽然在本例中可能是相当小的一点)是,随着您处理更多的数据,您通常希望生成更多的垃圾,因此花费更多的时间进行垃圾收集。由于串行收集器在执行其工作时会停止所有其他处理,因此这不仅可以加快垃圾收集速度,还可以防止在这段时间内生成更多垃圾。

现在,为什么我说在这种情况下这可能是一个次要的贡献者?这很简单:串行收集器在五个小时中只用了一秒钟多一点。尽管在大约1.3秒的时间内没有完成任何其他工作,但这只占5个小时的很小的百分比,可能对您的总体吞吐量没有太大的影响(如果有的话)。

摘要:串行垃圾收集的问题不在于它总体上占用了过多的时间--而在于当您碰巧需要快速响应时,如果它恰好停止运行,它可能会非常不方便。同时,我应该补充说,只要您的收集周期很短,这仍然可以是相当小的。理论上,其他形式的GC大多限制了最坏的情况,但实际上(例如,通过限制堆大小),您通常也可以限制串行收集器的最大延迟。

票数 4
EN

Stack Overflow用户

发布于 2012-03-16 22:40:34

在2012年的QCon Conference大会上,有一位推特工程师在这个话题上做了一次精彩的演讲--你可以在here上观看。

它讨论了Hotspot JVM内存和垃圾收集中的各种“代”(Eden、Survivor、Old)。特别要注意的是,ConcurrentMarkAndSweep中的“并发”只适用于老一代,即挂起一段时间的对象。

短暂的对象是来自“伊甸园”一代的GCd -这很便宜,但无论你选择哪种GC算法,它都是一个“停止世界”的GC事件!

建议首先调整年轻一代,例如分配大量的新伊甸园,这样就有更多的机会让对象在年轻时死亡并被廉价回收。使用+PrintGCDetails、+PrintHeapAtGC、+PrintTenuringDistribution...如果你的存活率超过100%,那么就没有空间了,所以物体很快就会升级为旧的--这是很糟糕的。

当调整老一代时,如果延迟是最重要的,建议先尝试自动调整的ParallelOld (+自适应大小策略等),然后尝试内容管理,然后可能是新的G1GC。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/9738911

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档