代码之家  ›  专栏  ›  技术社区  ›  Gnoupi

有没有一种方法可以在Java中启动一个积极的、完整的垃圾收集?

  •  5
  • Gnoupi  · 技术社区  · 16 年前

    出于内存优化的原因,我在评测期间启动了垃圾收集器,以检查在处理对象之后是否正确地清理了它们。

    不过,仅仅调用垃圾收集器是不够的,而且似乎无法保证它将清理什么。

    有没有一种方法来调用它,以确保它能在分析条件下尽可能多地恢复(当然,这在生产中没有意义)?或者说“打几次电话”是“几乎确定”的唯一方法?

    4 回复  |  直到 16 年前
        1
  •  4
  •   Thomas Pornin    16 年前

    一般来说,“完全垃圾收集”的定义是错误的。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”标志启动,该标志用于转换 运行时.gc()

    还有一些注意事项:

    • JVM可能有一些后台连续活动,例如。 Timer 线程。某些活动可能是“隐藏的”,即不是由应用程序开发人员编写的代码。另外,请考虑AWT/Swing事件调度器线程。

    • GC运行可能会通过可终结的对象或软/弱/虚引用触发额外的异步活动。这样的活动必然是异步的,并且可能会运行无限长的时间。 运行时.gc() 不会等那件事结束。这实际上是一个定义问题:做什么

    • 没有什么能真正迫使上面的代码终止。。。

    对于“更完整”的GC,您可以使用JVMTI接口(调试器使用的接口),它允许您运行GC,但是 暂停目标JVM线程,这使得定义和实现“完整GC”状态变得更加容易。

        2
  •  4
  •   BalusC    16 年前

    强制分配最大可用内存量。当JVM在 OutOfMemoryError

    byte[] boom = new byte[512 * 1024 * 1024]; // Assuming 512MB
    

    显然是出于纯粹的测试原因:)

    另一个选择是使用更好的探查器。提供有关内存使用情况和符合GC条件的对象的更好报告的方法。

        3
  •  2
  •   matt b    16 年前

        4
  •  1
  •   Lucero    16 年前

    基本上,你能做的就是:

    Runtime r = Runtime.getRuntime();
    r.gc();
    

    然而,请记住,所有能以某种方式到达的引用都被认为是活着的,即使你认为它们不是。根据具体的GC和设置,这可能收集也可能不收集(大多数)不“活动”的内存。