-2

我正在阅读 Java 章节中关于垃圾收集器的思考,我发现了一个曾经运行过的示例。但我不知道为什么。

public class Book {

boolean checkedOut = false;

Book(boolean checkOut) {
    checkedOut = checkOut;
}

void checkIn() {
    checkedOut = false;
}

@Override
protected void finalize() {
    if (checkedOut) {
        System.out.println("Error: checked out");
    }
    // Normally, you’ll also do this:
    //super.finalize(); // Call the base-class version
}

public static void main(String[] args) {
    Book novel = new Book(true);
// Proper cleanup:
    novel.checkIn();
// Drop the reference, forget to clean up:
    new Book(true);
// Force garbage collection & finalization:
    System.gc();
    }
}

System.gc()即使内存没有用完,对对象的调用也应该强制完成。

因此,为什么程序输出错误:仅在连续执行 4-5 次后才签出?我不明白这一点,你能试着澄清一下吗?我希望每次调用 GC 时都会执行 finalize 方法,因此每次都应该提示检出错误。

谢谢

4

2 回答 2

3

你读过文档吗?

来自http://docs.oracle.com/javase/7/docs/api/java/lang/System.html#gc%28%29

调用 gc 方法表明Java 虚拟机花费精力回收未使用的对象,以使它们当前占用的内存可用于快速重用。当控制从方法调用返回时,Java 虚拟机已尽最大努力从所有丢弃的对象中回收空间。

(强调我的)

它并没有说“在此调用之后,您可以保证所有无根对象都将被回收并执行它们的终结器”。你给 GC 一个建议,看看是否有任何数据要回收,这将是一个好主意。仅此而已。

(此外,http://docs.oracle.com/javase/7/docs/api/java/lang/System.html#runFinalization%28%29可能更适合您实际想要发生的事情,因为代码您向我们展示了检查对象的终结器是否已执行,而不是对象是否已被垃圾收集)

于 2013-09-14T13:41:22.567 回答
1

一个对象完全有可能永远不会被垃圾收集(因此finalize永远不会被调用)。

这可能发生在对象永远不符合 gc的条件(因为它在 JVM 的整个生命周期内都可以访问)或者在对象变得符合条件和 JVM 停止运行之间实际上没有运行垃圾收集时(这通常发生在简单的测试程序)。

不能保证finalize()会被调用。

注意:如果您这样做是为了理解,那么它很好,但您应该避免System.gc()显式调用。

免责声明:我并不是说这是一种正确的做法。我只是想着在调用延迟之前是否有一些延迟,也许创建的对象会被 gc 检测到并且每次都会被收集。

解决方法(不保证工作)

Thread.sleep(10000); //try sleeping for a while before giving a call to gc
// Force garbage collection & finalization:
    System.gc();

在我的环境中连续打印 4 次所需的输出。

于 2013-09-14T13:41:37.840 回答