日期:2014-05-20  浏览次数:20730 次

System.gc()什么时候调用用户自定义的finalize()方法
public class Book {

boolean checkout = false;
Book(boolean checkout){
this.checkout = checkout;

}

void checkIn(){
checkout = false;
}

protected void finalize(){
if(checkout){
System.out.println("Error: Check out!");
}
}
}

public class TerminationCondition {

/**
 * @param args
 */
public static void main(String[] args) {
// TODO Auto-generated method stub
Book novel = new Book(true);
novel.checkIn();
new Book(true);
System.gc();
}

}
代码如上所示, 实际在eclipse中运行时,偶尔会输出"Error: Check out!",而不是每次都输出,请问一下这是为什么呢? 难道System.gc()不是每次执行的时候都会调用finalize()方法吗? 

------解决方案--------------------
楼主可以产生大量对象,不用System.gc(),会看到finalize()方法也运行。
------解决方案--------------------
个人理解,不保证正确:
可能是主线程先执行完了,导致看不到打印结果
可以在System.gc();后面加点东西看看效果。

参考api里的System.gc(),最好看英文的,中文版翻译的可能有错误。
引用
gc
public static void gc()Runs the garbage collector. 
Calling the gc method suggests that the Java Virtual Machine expend effort toward recycling unused objects in order to make the memory they currently occupy available for quick reuse. When control returns from the method call, the Java Virtual Machine has made a best effort to reclaim space from all discarded objects. 

The call System.gc() is effectively equivalent to the call: 

 Runtime.getRuntime().gc()
 
See Also:
Runtime.gc()

------解决方案--------------------
首先:system.gc()并不是你调用就马上执行的, 而是根据虚拟机的各种算法来来计算出执行垃圾回收的时间,另外,程序自动结束时不会执行垃圾回收的。
其次:对象被回收时,要经过两次标记,第一次标记,如果finalize被重写,或者finalize被调用过,那么垃圾回收并不会去执行finalize,第二次标记,如果对象不能在finalize中成功拯救自己,那真的就要被回收了

这里说得比较简单,要想深入理解,请参见《深入理解java虚拟机+jvm高级特性与最佳实践》中的垃圾收集器与内存分配策略,再次,请你运行一下一下代码:

public class FinalizeEscapeGC {
public static FinalizeEscapeGC gc=null;
public static void isAlive(){
System.out.println("yes,i am alive!!!");
}
public static void isDead(){
System.out.println("no, i am dead!!!");
}

@Override
protected void finalize() throws Throwable {
        super.finalize();
        System.out.println("Finalize method is executed!!!");
        gc=this;
        }
public static void main(String[] args) throws Throwable{
        gc=new FinalizeEscapeGC();
gc=null;
        System.gc();
        Thread.sleep(500);
        if(gc!=null)
         isAlive();