java 垃圾收集和线程
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/2085544/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Garbage Collection and Threads
提问by Hassan Syed
AFAIK when a GC is doing its thing the VM blocks all running threads -- or at least when it is compacting the heap. Is this the case in modern implementions of the CLR and the JVM (Production versions as of January 2010)? Please do not provide basic links on GC as I understand the rudimentary workings.
AFAIK 当 GC 做它的事情时,VM 会阻止所有正在运行的线程——或者至少在它压缩堆时。在 CLR 和 JVM (截至 2010 年 1 月的生产版本)的现代实现中是否就是这种情况?由于我了解基本工作原理,因此请不要提供有关 GC 的基本链接。
I assume global locking is the case as when compaction occurs references might be invalid during the move period, and it seems simplest just to lock the entire heap (i.e., indirectly by blocking all threads). I can imagine more robust mechanisms, but KISS often prevails.
我假设全局锁定是这种情况,因为在移动期间发生压缩时引用可能无效,并且锁定整个堆似乎最简单(即通过阻塞所有线程间接锁定)。我可以想象更强大的机制,但 KISS 经常占上风。
If I am incorrect my question would be answered by a simple explanation of the strategy used to minimise blocking. If my assumption is correct please provide some insight on the following two questions:
如果我不正确,我的问题将通过对用于最小化阻塞的策略的简单解释来回答。如果我的假设是正确的,请就以下两个问题提供一些见解:
If this is indeed the behaviour, how do heavyweight enterprise engines like JBOSS and Glassfish maintain a consistantly high TPS rate ? I did some googling on JBOSS and I was expecting to find something on a APACHE like memory allocator suited for web processing.
In the face of NUMA-esque architectures (potentially the near future) this sounds like a disaster unless the processes are CPU bound by thread and memory-allocation.
如果这确实是这种行为,那么像 JBOSS 和 Glassfish 这样的重量级企业引擎如何保持始终如一的高 TPS 率?我在 JBOSS 上进行了一些谷歌搜索,我期待在 APACHE 上找到适合 Web 处理的内存分配器之类的东西。
面对 NUMA 式架构(可能在不久的将来),这听起来像是一场灾难,除非进程受线程和内存分配的 CPU 限制。
采纳答案by Stephen C
The answer is that this depends on the garbage collection algorithms used. In some cases, you are correct that all threads are stopped during GC. In other cases, you are incorrect in that garbage collection proceeds while normal threads are running. To understand how GC's achieve that, you need a detailed understanding of the theory and terminology of garbage collectors, combined with an understanding of the specific collector. It is simply not amenable to a simple explanation.
答案是这取决于所使用的垃圾收集算法。在某些情况下,在 GC 期间停止所有线程是正确的。在其他情况下,您在正常线程运行时进行垃圾收集是不正确的。要了解 GC 如何实现这一点,您需要详细了解垃圾收集器的理论和术语,并结合对特定收集器的了解。它根本不适合简单的解释。
Oh yes, and it is worth pointing out that many modern collectors don't have a compaction phase per-se. Rather they work by copying live objects to a new "space" and zeroing the old "space" when they are done.
哦,是的,值得指出的是,许多现代收藏家本身并没有压缩阶段。相反,它们通过将活动对象复制到新的“空间”并在完成后将旧的“空间”归零来工作。
If I am incorrect my question would be answered by a simple explanation of the strategy used to minimise blocking.
如果我不正确,我的问题将通过对用于最小化阻塞的策略的简单解释来回答。
If you really want to understand how garbage collectors work, I recommend:
如果你真的想了解垃圾收集器的工作原理,我建议:
- "Garbage Collection: Algorithms for Automatic Dynamic Memory Management"by Richard Jones.
- "The Garbage Collection Handbook: The Art of Automatic Memory Management"by Richard Jones, Antony Hosking and Eliot Moss
- Richard Jones 的“垃圾收集:自动动态内存管理算法”。
- 《垃圾收集手册:自动内存管理的艺术》,作者:Richard Jones、Antony Hosking 和 Eliot Moss
... and beware that finding accurate, detailed, public descriptions of the internals of production garbage collectors is not easy. (Though in the case of the Hotspot GC's, you can look at the source code ...)
...并请注意,要找到生产垃圾收集器内部结构的准确、详细、公开的描述并不容易。(虽然在 Hotspot GC 的情况下,您可以查看源代码...)
EDIT:in response to the OP's comment ...
编辑:回应OP的评论......
"It seems it is as I thought -- there is no getting around the "stop the world" part."
“似乎和我想的一样——没有绕过“停止世界”的部分。”
It depends. In the case of the Java 6 Concurrent Collector, there are two pauses during the marking of the roots (including stacks), and then marking / copying of other objects proceeds in parallel. For other kinds of concurrent collector, read or write barriers are used while the collector is running to trap situations where the collector and application threads would otherwise interfere with each other. I don't have my copy of [Jones] here right now, but I also recall that it is possible to make the "stop the world" interval negligible ... at the cost of more expensive pointer operations and/or not collecting all garbage.
这取决于。在Java 6 Concurrent Collector的情况下,在标记根(包括堆栈)期间有两次暂停,然后并行进行其他对象的标记/复制。对于其他类型的并发收集器,在收集器运行时使用读取或写入屏障来捕获收集器和应用程序线程否则会相互干扰的情况。我现在这里没有 [Jones] 的副本,但我还记得有可能使“停止世界”间隔可以忽略不计......代价是更昂贵的指针操作和/或不收集所有垃圾。
回答by Aaron
You are correct that the garbage collector will have to pause all the application threads. This pause time can be reduduced with the sun JVM by using the concurrent collector which preforms some of the work without stopping the application, but it stll has to pause the application threads.
您是正确的,垃圾收集器将不得不暂停所有应用程序线程。Sun JVM 可以通过使用并发收集器来减少暂停时间,该收集器在不停止应用程序的情况下执行一些工作,但它仍然必须暂停应用程序线程。
See here http://java.sun.com/javase/technologies/hotspot/gc/gc_tuning_6.html#par_gcand here http://java.sun.com/javase/technologies/hotspot/gc/gc_tuning_6.html#cmsfor details on how the sun JVM manages garbage collection in the latest JVMs.
请参阅此处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 中的垃圾收集的详细信息。
For web applications I don't think this is an issue. As the user requests should complete within a small amount of time < 1s any temporary objects allocated to service the request should not exit the young generation (providing it is sized appropriately) where they are cleaned up very efficiently. Other data with longer lifecycles such as user sessions will hang around longer and can impact the time spent on major GC events.
对于 Web 应用程序,我认为这不是问题。由于用户请求应该在小于 1 秒的短时间内完成,因此任何分配给请求服务的临时对象都不应该退出年轻代(假设它的大小合适)在那里它们被非常有效地清理。其他生命周期较长的数据(例如用户会话)将停留更长时间,并可能影响花在主要 GC 事件上的时间。
On high TPS applications a common strategy is to run multiple instances of the application server either on the same or separate hardware using session affinity and load ballancing. By doing this the individual heap size per JVM is kept smaller which reduced the pause times for GC when performing a major collection. In general the database becomes the bottle neck rather than the application or JVM.
在高 TPS 应用程序上,一个常见的策略是使用会话亲缘关系和负载平衡在相同或不同的硬件上运行应用程序服务器的多个实例。通过这样做,每个 JVM 的单个堆大小保持较小,从而减少了执行主要收集时 GC 的暂停时间。一般来说,数据库成为瓶颈,而不是应用程序或 JVM。
The closest you might find to the concept of a web specific memory allocator in in J2EE is object/instance pooling that is performed by frameworks and application severs. For example in JBOSS you have EJB pools and database connection pools. However these objects are usually pooled because of thier high creation cost rather than the garbage collection overhead.
您可能会发现与 J2EE 中特定于 Web 的内存分配器概念最接近的是由框架和应用程序服务器执行的对象/实例池。例如,在 JBOSS 中,您有 EJB 池和数据库连接池。然而,这些对象通常是池化的,因为它们的创建成本高而不是垃圾收集开销。
回答by redcalx
I believe IBM have performed some research towards improving GC performance in multi-core systems which includes work on reducing or eliminating the 'everything stop' issue.
我相信 IBM 已经进行了一些研究,以提高多核系统中的 GC 性能,其中包括减少或消除“一切停止”问题的工作。
E.g. see: A Parallel, Incremental and Concurrent GC for Servers(pdf)
例如,请参阅: 服务器的并行、增量和并发 GC(pdf)
Or google something like "concurrent garbage collection ibm"
或者谷歌类似“并发垃圾收集ibm”
回答by Jon Harrop
AFAIK when a GC is doing its thing the VM blocks all running threads -- or at least when it is compacting the heap. Is this the case in modern implementions of the CLR and the JVM (Production versions as of January 2010) ?
AFAIK 当 GC 做它的事情时,VM 会阻止所有正在运行的线程——或者至少在它压缩堆时。在 CLR 和 JVM(截至 2010 年 1 月的生产版本)的现代实现中是否就是这种情况?
Both Sun's Hotspot JVM and Microsoft's CLR have concurrent GCs that stop-the-world only for short phases (to get a self-consistent snapshot of the global roots from which all live data are reachable) and not for entire collection cycles. I'm not sure about their implementations of compaction but that is a very rare occurrence.
Sun 的 Hotspot JVM 和 Microsoft 的 CLR 都有并发 GC,这些 GC 仅在短阶段停止(以获得全局根的自洽快照,从中可以访问所有实时数据),而不是整个收集周期。我不确定他们对压缩的实现,但这种情况非常罕见。
If this is indeed the behaviour, how do heavyweight enterprise engines like JBOSS and Glassfish maintain a consistantly high TPS rate?
如果这确实是这种行为,那么像 JBOSS 和 Glassfish 这样的重量级企业引擎如何保持始终如一的高 TPS 率?
The latency of those engines is orders of magnitude longer than the time taken to stop the world. Also, latencies are quoted as, for example, 95th percentile meaning that the latency will only be below the quoted time span 95% of the time. So compactions are unlikely to affect quoted latencies.
这些引擎的延迟比停止世界所需的时间长几个数量级。此外,延迟被引用为例如第 95 个百分位数,这意味着延迟将仅在 95% 的时间内低于引用的时间跨度。所以压缩不太可能影响引用的延迟。
回答by Paul Wagland
Current state of the art garbage collection for Java still involves occasional "stop the world" pauses. The G1 GC introduced on Java 6u14 does most of it's work concurrently, however, when memory is really low, and it needs to compact the heap, then it has to ensure that no-one messes with the heap underneath it. This requires that nothing else is allowed to proceed. To find out more about the G1 GC, look at the presentations from Sun.
当前最先进的 Java 垃圾收集仍然涉及偶尔的“停止世界”暂停。Java 6u14 上引入的 G1 GC 并发执行大部分工作,但是,当内存非常低并且需要压缩堆时,它必须确保没有人弄乱它下面的堆。这要求不允许进行任何其他操作。要了解有关 G1 GC 的更多信息,请查看Sun的演示文稿。
回答by Matthew Wilson
There are a number of GC algorithms available with Java, not all of which block all running threads. For example, you can use -XX:+UseConcMarkSweepGC which runs concurrently with the app (for collection of the tenured generation).
Java 有许多可用的 GC 算法,但并非所有算法都会阻塞所有正在运行的线程。例如,您可以使用与应用程序同时运行的 -XX:+UseConcMarkSweepGC(用于收集年老代)。

