垃圾收集和线程

时间:2010-01-18 11:15:24

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

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

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

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

  1. 如果这确实是行为,那么像JBOSS和Glassfish这样的重量级企业引擎如何保持一致的高TPS率?我在JBOSS上做了一些谷歌搜索,我期待在APACHE上找到适合网络处理的内存分配器。

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

6 个答案:

答案 0 :(得分:16)

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

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

  

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

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

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

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

  

“看起来就像我想的那样 - 没有绕过”停止世界“的部分。”

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

答案 1 :(得分:2)

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

有关sun JVM如何管理最新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

对于Web应用程序,我不认为这是一个问题。因为用户请求应该在少量时间内完成< 1s分配给服务请求的任何临时对象都不应退出年轻代(如果大小合适),它们可以非常有效地清理它们。其他具有较长生命周期的数据(如用户会话)将会更长时间停留,并可能影响主要GC事件所花费的时间。

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

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

答案 2 :(得分:1)

我相信IBM已经开展了一些改善多核系统GC性能的研究,其中包括减少或消除“一切停止”问题的工作。

E.g。看到: A Parallel, Incremental and Concurrent GC for Servers(pdf)

或谷歌类似“并发垃圾收集ibm”

答案 3 :(得分:1)

  

AFAIK当GC正在执行其操作时,VM阻止所有正在运行的线程 - 或者至少在压缩堆时。在CLR和JVM的现代实现中是这种情况(截至2010年1月的生产版本)吗?

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

  

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

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

答案 4 :(得分:0)

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

答案 5 :(得分:0)

Java的当前最先进的垃圾收集仍然偶尔会“停止世界”暂停。在Java 6u14上引入的G1 GC可以同时完成大部分工作,但是,当内存非常低时,它需要压缩堆,然后它必须确保没有人混淆堆下面的堆。这要求不允许任何其他事情继续进行。要了解有关G1 GC的更多信息,请查看presentations from Sun