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(),最好看英文的,中文版翻译的可能有错误。
[解决办法]
首先: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();
else
isDead();
gc=null;
System.gc();
Thread.sleep(500);
if(gc!=null)
isAlive();
else
isDead();
}
}
[解决办法]
避免使用终结函数,该方法不能保证一定执行,并且依赖JVM的具体实现,有可能根本不会被执行,详情请见effective java
[解决办法]
觉得java就不应该设计有finalize这个方法。
[解决办法]
我给你详细讲解下吧,,,首先system.gc调用后不是马上执行,,,
咱们用的虚拟机一般都是sun的hotspot,以下描述都是针对hotspot虚拟机,当然其他虚拟机也差不多,
,,他是根据跟搜索算法判断哪些垃圾需要回收
GCROOT就是跟,,垃圾回收又分为新生代和老生代,你刚new的对象,占用的内存也不会超过
直接进入老生代的标准,,因为可以存活下来的对象很少,,,所以新生代采用复制的算法,,
如果你的对象实例没有到达这个跟的引用链,,那么就会被标记为要回收的对象,新生代的内存
模型分为eden space和s0以及s1,,被标记为要清除的对象后,会进行筛选,如果这个对象没被调用过
finalize方法并且重写了finalize方法,,那么就会把这个对象加入一个叫F-queue的队列中,然后
虚拟机会启动一个优先级较低的finalizer线程去执行这个对象的finalize方法,如果在这些方法结束之前
这个对象又有了一个引用链到达gc root 那么 这个对象这次就是自救成功了, 垃圾收集器不会手机他,,
当然同一个对象实例的finalize方法只会被调用一次,也就是说只有一次自救机会。所以只有第一次收集
才会输出
[解决办法]
finalize 是java调用本地程序的时候,比如C++,要释放资源的代码放finalize里面
[解决办法]
这和内存的使用情况有关,很难准确控制。
一般E区、S0区、S1区这三个新区堆以O区这个持久对象区及任意一个达到100%会触发YGC,而P区满了会触发FGC。
所以被调用有三种情况
1. 对象失效后,被立刻回收,此时finalize方法被调用。
2. 在E、S0、S1或者O区中的时候,所处堆区达到100%,该区已经失效的所有对象被回收,会触发finalize方法。
3. P区达到100%,jvm中断当前所有进程,回收所有已经失效的对象,触发finalize方法。
[解决办法]
虽然显示的调用system.gc(),但是java不一定就回去执行垃圾回收,他有自己的判断。finalize是在对象回收的时候才调用。
[解决办法]
调用的时机是不能确定的。垃圾收集是一项比较耗费资源的操作,而且垃圾线程的线程优先级较低。基本上由JVM实现及操作系统的调度算法决定何时才进行垃圾收集。事实上,finalize()应该是在二次标记前的最后一次拯救对象的机会。最好不要用这个方法。
[解决办法]
我偶尔看到一个说同时调用下面两个方法, 系统会立即清理内存。
System.gc();
System.runFinalization();
我也没验证过,不知是真是假!