为什么最终没有被召唤?

时间:2011-10-16 20:06:14

标签: java garbage-collection

我对java中的垃圾收集器有几个问题。

问题1.据我所知,当对象超出范围且JVM即将收集垃圾时,会调用finalize()。我认为垃圾收集器会自动调用finalize()方法,但在这种情况下它似乎不起作用。解释是什么?为什么我需要显式调用finalize()方法?

public class MultipleConstruct {
    int x,y;    
    public MultipleConstruct(int x)
    {
        this.x= x;
        y=5;        
        System.out.println("ONE");
    }

    @Override
    protected void finalize() throws Throwable {
        // TODO Auto-generated method stub
        super.finalize();
        System.out.println("FINALIZED");
    }
    public static void main(String[] args) throws Throwable {
        MultipleConstruct construct = new MultipleConstruct(3);
    }
}

Q2。另外,什么时候调用垃圾收集器?我理解gc是一个守护程序线程,由JVM根据剩余的堆大小调用。这是否意味着,JVM等待程序使用资源的阈值限制,然后通知gc扫描垃圾对象。

编辑: gc如何解决循环引用?

4 个答案:

答案 0 :(得分:8)

有很多finalize()方法,坦率地写了很多,但简而言之:

如果对象在其finalize方法(如果有)运行后仍无法访问,则处于已完成状态。最终的对象正在等待释放。请注意,VM实现控制何时运行终结器。你几乎总是更好地做自己的清理,而不是依靠终结器。使用终结器还可以留下在不确定的时间内无法恢复的关键资源。

在你的情况下,它不打印的原因是你不知道终结器线程何时会调用finalize()方法。发生的事情是该程序在任何可以打印之前终止。检查一下: 编辑主代码中的代码(注意:这不是保证,也不应该依赖它,但它仍会打印一段时间)

for(int i =0;i<1000000;i++)
    {
        MultipleConstruct construct = new MultipleConstruct(3);
        construct = null;
    }

使用finalize()有很多缺点,从在对象构造中花费更多时间到内存泄漏和内存不足的可能性。如果你强烈引用finalize()中的同一个对象,那么它永远不会被第二次调用,从而可能使系统处于不希望的状态等等...... 你应该使用finalize()的唯一地方是作为一个安全网来处理任何资源,比如InputStream使用它来关闭(这也没有保证它会在你的程序还活着的时候运行)。另一个使用它的地方是使用垃圾收集器无法控制的本机。

欲了解更多信息,请访问:

  

http://jatinpuri.com/?p=106

答案 1 :(得分:5)

q1)当对象被垃圾收集时调用finalize方法,因此,如果没有执行GC,则可能不会调用终结器。您只需要调用super来保留Object实现提供的行为。

q2)执行GC的确切时刻取决于很多因素,例如:您正在使用的JVM,调整参数,可用堆的数量等等。因此,它不仅依赖于使用的堆阈值。您也可以要求通过System.gc()执行GC,但您无法保证是否以及何时实际执行。 您可以在http://java.sun.com/performance/reference/whitepapers/tuning.html

中找到有关如何配置GC的一些详细信息

答案 2 :(得分:2)

它最终会被 或根本不被称为

基本上GC会扫描堆中的所有无法访问的内容并在那些上运行终结器(之后需要再次证明它无法被释放)

然而,GC可能需要一段时间(实际上是未定义的并且实际上依赖于程序行为)才能找到它,这就是为什么你不应该真正依赖它来处理关键数据

编辑:对于循环引用,它区分具有finalize方法的对象和没有

的对象

对于要释放的对象(从主内存中删除),任何代码都可能无法访问它(这包括仍然需要运行的终结器)

当具有终结器的2个对象有资格获得终结器运行时,GC任意选择一个对象并在其上运行终结器然后它可以运行另一个对象

请注意,终结器可以运行,而对象的字段可能已经或可能尚未最终确定

答案 3 :(得分:-3)

在垃圾回收期间自动调用

finalize()方法。 System.gc()方法强制调用垃圾收集器。但我们必须先破坏物体。 例如:

     public class Sample 
{
    public Sample()
    {
        System.out.println("Object created");
    }
    @Override
    public void finalize()
    {
        System.out.println("Object Destroyed");
    }
    public static void main(String args[])
    {
        Sample x=new Sample();
        Sample y=new Sample();

        x=null;
        y=null;

        System.gc();
    }
}