Java 垃圾收集器示例没有';托住

Java 垃圾收集器示例没有';托住,java,garbage-collection,Java,Garbage Collection,我正在阅读java中关于垃圾收集器的思考一章,我发现了一个曾经运行过的示例。但我不明白为什么 public class Book { boolean checkedOut = false; Book(boolean checkOut) { checkedOut = checkOut; } void checkIn() { checkedOut = false; } @Override protected void finalize() { if (checkedO

我正在阅读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方法,因此每次都应该提示签出错误


谢谢

您看过文档了吗

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

(强调矿山)

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


(另外,可能更符合您实际希望发生的事情,因为您向我们展示的代码检查对象的终结器是否已执行,而不是对象是否已被垃圾收集)

完全有可能对象从未被垃圾收集过(因此,
finalize
从未被调用)

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

无法保证将调用
finalize()

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

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

解决方法(不保证有效)


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

这个问题还不清楚。你能详细说明你期望的是什么行为吗?我没有尝试去探究你的例子,但是运行
finalize
并不能保证。请参阅我在代码中提供的解决方法。在我的环境中,它连续执行了4次。孩子们,这就是为什么您应该始终使用正确的抽象(即,RAII和它提供的确定性对象销毁),而不是错误的抽象(即,GC不保证对象的生存期)。所以这只是一个建议?我到底想强迫它什么?你为什么要强迫它?我在寻求知识。我在书中找到了这个例子,想知道为什么它不起作用。作者公开了它,因为它必须始终执行最终定稿。答案是,“你不想强迫它”。GC在需要运行时运行。通常,手动调用函数只会让程序慢一点(GC在收集大量内存时效率最高。)我明白这一点。我想指出怎么做,我知道这样做更糟糕。我只是在寻找和学术目的如何做到这一点。似乎使用gc和runFinalization的组合调用终结方法。我想我们可以在这里结束讨论;)在哪个星球上“阻塞线程10秒”是一个有用的解决方法?@jalf我刚刚发布了它,因为在gc有机会运行之前会有一些延迟。我也在我的环境中尝试过。如果它看起来很模糊,我会删除它吗?你有什么建议?
Thread.sleep(10000); //try sleeping for a while before giving a call to gc
// Force garbage collection & finalization:
    System.gc();