如何保证的finalize()总是叫(在Java中锻炼思维)(How to ensure final

2019-06-27 03:51发布

我慢慢地布鲁斯Eckel的用Java第四版思想工作,和下面的问题我难住了:

与该打印的消息的finalize()方法创建的类。 在main(),创建类的对象。 修改前面的练习,使您的finalize()总是会被调用。

这是我所编码:

public class Horse {
    boolean inStable;
    Horse(boolean in){
        inStable = in;
    }   
    public void finalize(){
        if (!inStable) System.out.print("Error: A horse is out of its stable!");
    }
}
public class MainWindow {
    public static void main(String[] args) {
        Horse h = new Horse(false);
        h = new Horse(true);
        System.gc();
    }
}

它创建了一个新的Horse与布尔对象inStable设置为false 。 现在,在finalize()方法,检查是否inStablefalse 。 如果是,它打印一条消息。

不幸的是,不打印信息。 由于条件的计算结果为true ,我的猜测是finalize()不会被调用摆在首位。 我已经运行程序无数次,看到错误消息只打印了几次。 我的印象是,当System.gc()调用,垃圾收集器会收集未引用的任何对象。

谷歌搜索一个正确的答案给了我这个链接 ,取得更详细的,复杂的代码。 它采用了我以前从未见过的方法,如System.runFinalization() Runtime.getRuntime()System.runFinalizersOnExit()

是谁能够给我一个更好地了解finalize()的工作原理,以及如何迫使它运行,或步行通过我什么是解决方案代码正在做?

Answer 1:

当垃圾收集器找到一个对象,它是符合回收,但有一个finalizer它不会立即释放它。 垃圾收集器会尝试尽可能快地完成,所以它只是将对象添加到与挂起的终结对象的列表。 终结以后在一个单独的线程调用。

你可以告诉系统,试图通过调用方法立即运行挂起终结System.runFinalization垃圾回收之后。

但是,如果你想强制终结运行,你必须自己调用它。 垃圾收集器并不保证任何对象将被收集或将终结将被调用。 它不仅使一个“尽力而为”。 然而,它是罕见的,你会需要强制终结在实际运行代码。



Answer 2:

玩具的场景之外,它通常是不可能的,以确保finalize将始终以没有“有意义”的引用存在哪些对象被调用,因为垃圾收集器无法知道它引用“有意义”的方式。 例如,一个ArrayList状物体可能有一个“清除”方法,将其计数到零,并使得支持数组资格中的所有元素由未来被覆盖Add通话,但实际上并没有明确在后盾元素阵列。 如果对象具有大小为50的阵列,并且其Count是23,那么有可能是由码所能检查存储在所述阵列的最后27位的参考文献中没有执行路径,但就没有办法让垃圾-collector知道。 因此,垃圾收集器将永远不会调用finalize在那些时隙的对象,除非或直到容器改写那些阵列插槽,容器抛弃了阵列(或许有利于较小的一个的),或在容器的所有根引用本身被破坏或以其他方式不复存在。

有各种手段来鼓励系统调用finalize对其中无强根引用发生在存在任何对象(这似乎是问题的点,和其他的答案已经被覆盖),但我觉得要注意这一点很重要设定到强根引用存在哪些对象,以及该组的代码可能感兴趣的对象之间的区别。两组很大程度上重叠,但每一组所用的其它不包含对象。 对象的当GC确定的对象将不再存在,但为终结的存在finalizers`运行; 这可能会或可能不会与时间码,他们不再是感兴趣的人重合。 虽然这将是有益的,如果一个可能会导致终结报告已不再是所有感兴趣的对象上运行,这是一般不可能的。



Answer 3:

呼叫到garabage集气器( System.gc() )方法来说明 Java虚拟机了一些努力,以便使他们当前占用快速重用(即它只是一个建议到JVM,并执行内存回收未使用的对象不结合它,然后有执行的操作,它可以或可以不这样做)。 当从方法调用控制返回时,Java虚拟机已经从所有丢弃的对象中回收了空间最大的努力。 最后确定()由对象的垃圾收集器调用时垃圾回收器确定不存在该对象的更多引用



Answer 4:

运行新的构造函数()和System.gc()的两倍以上。

public class Horse {
    boolean inStable;
    Horse(boolean in){
        inStable = in;
    }   
    public void finalize(){
        if (!inStable) System.out.print("Error: A horse is out of its stable!");
    }
}
public class MainWindow {
    public static void main(String[] args) {
        for (int i=0;i<100;i++){
            Horse h = new Horse(false);
            h = new Horse(true);
            System.gc();
        }
    }
}  


Answer 5:

下面是我工作(部分,但它确实说明了想法):

class OLoad {

    public void finalize() {
        System.out.println("I'm melting!");
    }
}

public class TempClass {

    public static void main(String[] args) {
        new OLoad();
        System.gc();
    }
}

行新的Oload(); 是卓有成效的,因为它创建不带任何附加参考的对象。 这有助于System.gc()的运行finalize()方法,因为它检测到无参考的对象。 话说类似的Oload 01 =新的Oload(); 是行不通的,因为它会创造生活,直到)的主要结束(参考。 不幸的是,这个工程 。 正如其他人所指出的,没有办法保证的finalize()将总是叫,除了自己调用它。



文章来源: How to ensure finalize() is always called (Thinking in Java exercise)