什么决定垃圾收集器何时真正收集?它是在一定时间后还是在用完一定数量的内存后发生的?还是有其他因素?
原文由 nalo 发布,翻译遵循 CC BY-SA 4.0 许可协议
什么决定垃圾收集器何时真正收集?它是在一定时间后还是在用完一定数量的内存后发生的?还是有其他因素?
原文由 nalo 发布,翻译遵循 CC BY-SA 4.0 许可协议
你可以试试这个小程序来检查 GC 的行为
public class GCTest {
final int NELEMS = 50000;
void eatMemory() {
int[] intArray = new int[NELEMS];
for (int i=0; i<NELEMS; i++) {
intArray[i] = i;
}
}
public static void main (String[] args) {
GCTest gct = new GCTest();
// Step 1: get a Runtime object
Runtime r = Runtime.getRuntime();
// Step 2: determine the current amount of free memory
long freeMem = r.freeMemory();
System.out.println("free memory before creating array: " + freeMem);
// Step 3: consume some memory
gct.eatMemory();
// Step 4: determine amount of memory left after consumption
freeMem = r.freeMemory();
System.out.println("free memory after creating array: " + freeMem);
// Step 5: run the garbage collector, then check freeMemory
r.gc();
freeMem = r.freeMemory();
System.out.println("free memory after running gc(): " + freeMem);
}
}
可能的输出——你的情况可能不同
free memory before creating array: 4054912
free memory after creating array: 3852496
free memory after running gc(): 4064184
检查此链接 http://www.devdaily.com/java/edu/pj/pj010008/
原文由 Xinus 发布,翻译遵循 CC BY-SA 2.5 许可协议
8 回答6k 阅读
1 回答4.1k 阅读✓ 已解决
3 回答2.3k 阅读✓ 已解决
2 回答3.2k 阅读
2 回答3.9k 阅读
1 回答2.2k 阅读✓ 已解决
3 回答1.6k 阅读✓ 已解决
它在确定是时候运行时运行。分代垃圾收集器的一个常见策略是在第 0 代内存分配失败时运行收集器。也就是说,每次分配一小块内存时(大块通常直接放入“老”代),系统会检查 gen-0 堆中是否有足够的可用空间,如果没有,则运行GC释放空间以便分配成功。然后将旧数据移动到 gen-1 堆,当空间用完时,GC 会对其进行收集,将存在时间最长的数据升级到 gen-2 堆,依此类推。所以 GC 不只是“运行”。它可能只在 gen-0 堆上运行(大多数集合都会这样做),或者它可能会检查每一代是否真的需要释放大量内存(很少需要)。
但这远非 唯一 的策略。并发 GC 在后台运行,在程序运行时进行清理。一些 GC 可能作为每个内存分配的一部分运行。增量收集器可能会这样做,在每次内存分配时扫描几个对象。
垃圾收集器的全部要点是它应该只做它自己的事情而不需要用户的任何输入。所以一般来说,你不能也不应该预测它什么时候会运行。
我相信 Suns JVM 不久前获得了分代 GC(也许是 v1.6?我已经很久没有编写 Java 代码了,所以对此不确定,但我记得不久前我感到很惊讶,当时的卖点之一是新版本是“一代 GC”。尤其是因为 .NET 从第一天起就有了一个。)
其他 JVM 当然可以自由选择他们喜欢的策略。
编辑: 上面关于 Java 和分代 GC 的部分是不正确的。请参阅下面的更多细节:
1.0 和 1.1 虚拟机使用标记清除收集器,它可以在垃圾收集后对堆进行分段。从 Java 1.2 开始,虚拟机切换到分代收集器,它具有更好的碎片整理行为(请参阅 Java 理论与实践:垃圾收集与性能)。
所以 Java 实际上有很长时间的分代 GC。 Java 6 中的新增功能是 Java 6u14 中提供的垃圾优先垃圾收集器 (G1)。根据 声称 1.6.0_14 中发布的文章: 默认情况下未启用。并行收集器仍然是默认的 GC,并且是普通家庭使用的最高效的 GC。 G1 旨在成为并发收集器的替代品。它旨在提高可预测性,并通过内存区域设计实现快速分配。