Java 垃圾收集器 - 它什么时候收集?
是什么决定了垃圾收集器何时真正收集?它是在一定时间后发生还是在一定数量的内存用完后发生?还是有其他因素?
What is it that determines when the garbage collector actually collects? Does it happen after a certain time or after a certain amount of memory have been used up? Or are there other factors?
推荐答案
它在确定是时候运行时运行.分代垃圾收集器的一个常见策略是在第 0 代内存分配失败时运行收集器.也就是说,每次分配一小块内存(大块通常直接放入老"代)时,系统都会检查 gen-0 堆中是否有足够的可用空间,如果没有,它会运行GC 释放空间以使分配成功.然后将旧数据移动到 gen-1 堆,当空间用完时,GC 会在其上运行一个集合,将存在时间最长的数据升级到 gen-2 堆,依此类推.所以GC不只是运行".它可能只在第 0 代堆上运行(大多数集合都会这样做),或者它可能会检查每一代是否真的需要释放大量内存(这很少需要).
It runs when it determines that it is time to run. A common strategy in generational garbage collectors is to run the collector when an allocation of generation-0 memory fails. That is, every time you allocate a small block of memory (big blocks are typically placed directly into "older" generations), the system checks whether there's enough free space in the gen-0 heap, and if there isn't, it runs the GC to free up space for the allocation to succeed. Old data is then moved to the gen-1 heap, and when space runs out there, the GC runs a collection on that, upgrading the data which has been there longest to the gen-2 heap, and so on. So the GC doesn't just "run". It might run on the gen-0 heap only (and most collections will do just that), or it might check every generation if it really has to free up a lot of memory (which is only necessary fairly rarely).
但这远非唯一策略.并发 GC 在后台运行,在程序运行时进行清理.某些 GC 可能会作为每个内存分配的一部分运行.增量收集器可能会这样做,在每次内存分配时扫描一些对象.
But this is far from the only strategy. A concurrent GC runs in the background, cleaning up while the program is running. Some GC's might run as part of every memory allocation. An incremental collector might do that, scanning a few objects at every memory allocation.
垃圾收集器的全部意义在于它应该只做自己的事情,而不需要用户的任何输入.所以一般来说,你不能也不应该预测它什么时候运行.
The entire point in a garbage collector is that it should just do its thing without requiring any input from the user. So in general, you can't, and shouldn't, predict when it'll run.
我相信 Suns JVM 不久前获得了分代 GC(也许是 v1.6?我很久没有编写 Java 代码了,所以对此不确定,但我记得不久前感到惊讶,当时新版本的卖点之一是一代代 GC".尤其是因为 .NET 从第一天开始就有了.)
其他 JVM 当然可以自由选择他们喜欢的任何策略.
Other JVM's are of course free to pick whichever strategy they like.
上面关于 Java 和分代 GC 的部分是不正确的.详情见下文:
The above part about Java and generational GC is not true. See below for more details:
1.0 和 1.1 虚拟机使用标记清除收集器,它可以在垃圾收集后对堆进行分段.从 Java 1.2 开始,虚拟机切换到分代收集器,它具有更好的碎片整理行为(请参阅 Java 理论与实践:垃圾收集与性能).
The 1.0 and 1.1 Virtual Machines used a mark-sweep collector, which could fragment the heap after a garbage collection. Starting with Java 1.2, the Virtual Machines switched to a generational collector, which has a much better defragmentation behavior (see Java theory and practice: Garbage collection and performance).
所以 Java 实际上有一个分代 GC 很长时间了.Java 6 中的新功能是 Java 6u14 中提供的 Garbage-First 垃圾收集器 (G1).根据 声称在 1.6.0_14 发布的文章:未启用默认情况下.并行收集器仍然是默认的 GC,并且是普通家庭使用的最有效的 GC.G1 旨在成为并发收集器的替代方案.它被设计为更可预测,并通过内存区域设计实现快速分配.
So Java actually has a generational GC for ages. What's new in Java 6 is the Garbage-First garbage collector (G1) that is available in Java 6u14. According to the article claiming the release in 1.6.0_14: It is not enabled by default. The parallel collector is still the default GC and is the most efficient GC for common household usage. G1 is meant to be an alternative for the concurrent collector. It is designed to be more predictable and enable fast allocation with memory regions design.
相关文章