【问题标题】:Garbage Collection and Threads垃圾收集和线程
【发布时间】:2011-01-06 07:58:02
【问题描述】:

AFAIK 当 GC 正在做它的事情时,VM 会阻塞所有正在运行的线程——或者至少在它压缩堆时。在 CLR 和 JVM (截至 2010 年 1 月的生产版本) 的现代实现中是否是这种情况?请不要提供有关 GC 的基本链接,因为我了解基本的工作原理。

我假设全局锁定是这种情况,因为当压缩发生时,引用可能在移动期间无效,并且锁定整个堆似乎最简单(即通过阻塞所有线程间接)。我可以想象更强大的机制,但 KISS 经常占上风。

如果我不正确,我的问题将通过对用于最小化阻塞的策略的简单解释来回答。如果我的假设是正确的,请对以下两个问题提供一些见解:

  1. 如果这确实是这种行为,那么 JBOSS 和 Glassfish 等重量级企业引擎如何保持始终如一的高 TPS 率?我在 JBOSS 上进行了一些谷歌搜索,我期待在 APACHE 上找到适合 Web 处理的内存分配器之类的东西。

  2. 面对 NUMA 式架构(可能在不久的将来),这听起来像是一场灾难,除非进程受线程和内存分配的 CPU 限制。

【问题讨论】:

    标签: java clr memory-management blocking garbage-collection


    【解决方案1】:

    Java 有许多可用的 GC 算法,但并非所有算法都会阻塞所有正在运行的线程。例如,您可以使用 -XX:+UseConcMarkSweepGC 与应用程序同时运行(用于收集终身代)。

    【讨论】:

    • 它们都会在需要进行全局GC时偶尔阻塞正在运行的线程。并发 GC 确实尝试以并发方式完成大部分工作。 java.sun.com/javase/technologies/hotspot/gc/…>
    • 又名(主要是)并发标记扫描。 (大部分)很重要。
    • 其他 JVM 有完全并发的 GC。
    【解决方案2】:

    答案是这取决于所使用的垃圾收集算法。在某些情况下,您在 GC 期间停止所有线程是正确的。在其他情况下,您在正常线程运行时进行垃圾收集是不正确的。要了解 GC 是如何实现这一点的,您需要详细了解垃圾收集器的理论和术语,并结合对特定收集器的了解。这根本不适合简单的解释。

    哦,是的,值得指出的是,许多现代收集器本身并没有压实阶段。相反,它们通过将活动对象复制到新的“空间”并在完成后将旧的“空间”归零来工作。

    如果我不正确,我的问题将通过对用于最小化阻塞的策略的简单解释来回答。

    如果你真的想了解垃圾收集器的工作原理,我建议:

    ...请注意,要找到生产垃圾收集器内部的准确、详细、公开的描述并不容易。 (虽然在 Hotspot GC 的情况下,您可以查看源代码...)

    编辑:回应 OP 的评论 ...

    “似乎和我想的一样——没有绕过“停止世界”的部分。”

    这取决于。在Java 6 Concurrent Collector 的情况下,在标记根(包括堆栈)期间有两次暂停,然后其他对象的标记/复制并行进行。对于其他类型的并发收集器,在收集器运行时使用读或写屏障来捕获收集器和应用程序线程否则会相互干扰的情况。我现在没有 [Jones] 的副本,但我还记得有可能使“停止世界”间隔可以忽略不计……代价是更昂贵的指针操作和/或不收集所有垃圾。

    【讨论】:

    • (+1) 肯定会买那本书。我想进一步了解的一点是“复制到新的和更新程序”之后会发生什么?大概所有引用都是通过阻塞所有线程来更新的?或者它是一个迭代过程?
    • 据我所知,即使是最并发的垃圾收集器也会为他们的一些工作“停止世界”,尽管大多数任务确实是同时运行的。然而,JVM 6 中的 CMS 收集器在 stop-the-world 阶段确实使用了所有可用的 CPU。
    • @edgar 谢谢你,“CMS-collector”有用的搜索词——有时间我会查一下细节。似乎正如我所想的那样 - 没有绕过“停止世界”的部分。对这些全局锁定阶段如何影响严重生产服务器的 TPS 速率(就像我在问题中提到的那些)有一些假设或一些标准数字会很有趣。
    • 关于 TPS:你完全错了!您通常可以将延迟(以毫秒为单位,越低越好)与吞吐量(以 TPS 为单位,越高越好)进行交易。低延迟算法的吞吐量通常低于替代方案:高吞吐量算法通常也会引入更高的延迟。如果您主要担心 TPS(典型的服务器负载),请不要担心 stop-the-world 阶段的长度。它会相对较长,但不会影响您的 TPS。
    • @Hassan - @edgar 是对的。最大化 TPS 的方法是使用总开销最低的 GC,而不是最小化暂停时间的 GC。
    【解决方案3】:

    垃圾收集器必须暂停所有应用程序线程是正确的。 Sun JVM 可以通过使用并发收集器来减少这种暂停时间,该收集器在不停止应用程序的情况下执行一些工作,但它必须暂停应用程序线程。

    请参阅此处http://java.sun.com/javase/technologies/hotspot/gc/gc_tuning_6.html#par_gc 和此处http://java.sun.com/javase/technologies/hotspot/gc/gc_tuning_6.html#cms,了解有关 sun JVM 如何在最新 JVM 中管理垃圾收集的详细信息。

    对于网络应用程序,我认为这不是问题。由于用户请求应在小于 1 秒的时间内完成,因此分配给请求服务的任何临时对象不应退出年轻代(只要其大小合适),它们会被非常有效地清理。其他生命周期较长的数据(例如用户会话)会保留更长时间,并可能影响花费在主要 GC 事件上的时间。

    在高 TPS 应用程序上,一种常见的策略是使用会话亲和性和负载平衡在相同或单独的硬件上运行应用程序服务器的多个实例。通过这样做,每个 JVM 的单个堆大小保持较小,从而减少了执行主要收集时 GC 的暂停时间。一般来说,数据库会成为瓶颈,而不是应用程序或 JVM。

    在 J2EE 中,您可能会发现与 Web 特定内存分配器概念最接近的是由框架和应用程序服务器执行的对象/实例池。例如,在 JBOSS 中有 EJB 池和数据库连接池。然而,这些对象通常是池化的,因为它们的创建成本很高,而不是垃圾收集开销。

    【讨论】:

    • (+1) 很好的讨论——我提炼出我需要查看并发的minor cycle 收集器,看看它的效果是什么。假设是 Web 服务器的 TPS 特性高度依赖于作为年轻代对象保留的请求分配。
    • @Hassan 是的,关于年轻代的段落是一个假设,将取决于您的应用程序,尽管您可以在 JVM 中调整代的大小。关键是你不应该太担心在处理请求时创建的临时对象,因为当前的分代垃圾收集器非常擅长清理这些。运行多个 JVM 可以帮助处理更长寿命的对象,例如用户会话,因为它们可以分布在 JVM 之间,这意味着每个 JVM 在主要收集期间需要检查的东西更少。
    • -1:GC 不必暂停所有线程(又名“stop the world”)。
    【解决方案4】:

    当前最先进的 Java 垃圾收集仍然涉及偶尔的“停止世界”暂停。 Java 6u14 引入的 G1 GC 的大部分工作都是并发的,但是,当内存非常低,并且需要压缩堆时,它必须确保没有人弄乱它下面的堆。这要求不允许进行任何其他操作。要了解有关 G1 GC 的更多信息,请查看presentations from Sun

    【讨论】:

    • -1:最先进的 Java 垃圾收集已经完全并发多年了。那里有 hard 实时 JVM...
    【解决方案5】:

    我相信 IBM 已经进行了一些研究以提高多核系统中的 GC 性能,其中包括减少或消除“一切都停止”问题的工作。

    例如看: A Parallel, Incremental and Concurrent GC for Servers(pdf)

    或者 google 类似“并发垃圾回收 ibm”的东西

    【讨论】:

      【解决方案6】:

      AFAIK 当 GC 正在做它的事情时,VM 会阻塞所有正在运行的线程——或者至少在它压缩堆时。在 CLR 和 JVM 的现代实现中是否是这种情况(截至 2010 年 1 月的生产版本)?

      Sun 的 Hotspot JVM 和 Microsoft 的 CLR 都具有并发 GC,这些 GC 仅在短阶段(以获取可访问所有实时数据的全局根的一致快照)而不是整个收集周期停止世界。我不确定他们的压缩实现,但这种情况非常罕见。

      如果确实是这种行为,那么 JBOSS 和 Glassfish 等重量级企业引擎如何保持始终如一的高 TPS 率?

      这些引擎的延迟比停止世界所需的时间长几个数量级。此外,延迟被引用为例如第 95 个百分位数,这意味着延迟将仅在 95% 的时间内低于引用的时间跨度。所以压缩不太可能影响引用的延迟。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-01-26
        • 1970-01-01
        相关资源
        最近更新 更多