出于内存优化的原因,我在分析过程中自行启动垃圾收集器,检查对象在处理后是否正确清理。
但是,对垃圾收集器的调用是不够的,而且似乎无法保证它能清除什么。
有没有办法调用它,以确保它能够在分析条件下尽可能多地恢复(当然,这在生产中没有意义)?或者“多次呼唤”是“几乎肯定”的唯一方法?
或者我只是误解了垃圾收集器的某些内容?
答案 0 :(得分:4)
强制分配可用的最大内存量。当JVM位于OutOfMemoryError
的角落时,它被迫运行GC。
byte[] boom = new byte[512 * 1024 * 1024]; // Assuming 512MB
显然出于纯粹的测试原因:)
另一种选择是使用更好的分析器。提供有关内存使用情况和GC符合条件的对象的更好报告的那个。
答案 1 :(得分:4)
一般而言,“完全垃圾收集”是不明确的。 GC检测到无法访问的对象,并回收它们。碰巧大多数GC实现在“循环”的基础上运行,并且一旦完成一个循环,就可以定义“回收空间”的声音概念。因此,如果你可以运行一个完整的循环并且该循环根本找不到可回收的空间,并且应用程序在其他方面“空闲”(例如没有更新指针),那么你可以说你已经暂时达到了“完全收集”的点
因此,您可能想要做类似的事情:
Runtime r = Runtime.getRuntime();
r.gc();
long f = r.freeMemory();
long m = r.maxMemory();
long t = r.totalMemory();
for (;;) {
r.gc();
long f2 = r.freeMemory();
long m2 = r.maxMemory();
long t2 = r.totalMemory();
if (f == f2 && m == m2 && t == t2)
break;
f = f2;
m = m2;
t = t2;
}
System.out.println("Full GC achieved.");
这段代码依赖于一些假设,其中最重要的是Runtime.gc()
不仅仅是一个“提示”,并且真正迫使一些GC活动。 Sun的JVM可以使用“-XX:-DisableExplicitGC”标志启动,该标志将Runtime.gc()
转换为无操作,有效地防止上述代码执行任何操作。
还有一些注意事项:
JVM可能有一些背景连续活动,例如Timer
个帖子。其中一些活动可能是“隐藏的”,即不是应用程序开发人员编写的代码。另外,请考虑AWT / Swing事件调度程序线程。
GC运行可能会触发额外的异步活动,通过可终结的对象或软/弱/幻像引用。这种活动必然是异步的,并且可以在无限的时间内运行。 Runtime.gc()
不会等到那个结束。这实际上是一个定义问题:如果还没有处理终结器和参考队列,那么你认为GC是“完整的”吗?
没有什么能够真正迫使上面的代码终止......
对于“更完整”的GC,您可以使用JVMTI接口(调试器使用的接口),它允许您运行GC但也以暂停目标JVM线程,这使得它更容易定义和实现“完整的GC”状态。
答案 2 :(得分:2)
不,你无法确定地启动完整的垃圾收集。
如果您正在尝试确保在您的性能分析尝试期间GC完全运行,要删除通常会被删除的任何对象(以便您可以找到实际泄漏的位置),那么它是最好的确保你的测试运行的时间足够长,你可以合理地预期GC会运行(或运行几次)。
答案 3 :(得分:1)
基本上,你所能做的就是:
Runtime r = Runtime.getRuntime();
r.gc();
但是,请记住,即使你认为它们不存在,所有可以通过某种方式获得的引用都被认为是活着的。根据确切的GC和设置,这可能会或可能不会收集(大多数)非“活着”的内存。