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

esse88 2013-02-26 09:28:18
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()方法吗?
...全文
554 16 打赏 收藏 转发到动态 举报
写回复
用AI写文章
16 条回复
切换为时间正序
请发表友善的回复…
发表回复
esse88 2013-03-06
  • 打赏
  • 举报
回复
总的来说,我认为这可能是JVM的处理机制造成的,至于JVM的处理机制现在就不去深究它,很感谢大家的回贴,结了。
eryueniliu 2013-02-27
  • 打赏
  • 举报
回复
好复杂,我看的眼花
sca4441479 2013-02-27
  • 打赏
  • 举报
回复
虽然显示的调用system.gc(),但是java不一定就回去执行垃圾回收,他有自己的判断。finalize是在对象回收的时候才调用。
赏金--猎人 2013-02-27
  • 打赏
  • 举报
回复
我偶尔看到一个说同时调用下面两个方法, 系统会立即清理内存。 System.gc(); System.runFinalization(); 我也没验证过,不知是真是假!
thomasLand 2013-02-27
  • 打赏
  • 举报
回复
调用的时机是不能确定的。垃圾收集是一项比较耗费资源的操作,而且垃圾线程的线程优先级较低。基本上由JVM实现及操作系统的调度算法决定何时才进行垃圾收集。事实上,finalize()应该是在二次标记前的最后一次拯救对象的机会。最好不要用这个方法。
esse88 2013-02-26
  • 打赏
  • 举报
回复
引用 3 楼 abc41106 的回复:
个人理解,不保证正确: 可能是主线程先执行完了,导致看不到打印结果 可以在System.gc();后面加点东西看看效果。 参考api里的System.gc(),最好看英文的,中文版翻译的可能有错误。 引用gc public static void gc()Runs the garbage collector. Calling the gc method ……
的确,在System.gc()方法后加了一条输出语句后,每次都能看到finalize()方法被调用了,这是为什么呢?如果说是因为没有加输出语句时主线程结束了看不到finalize()方法被调用的话,那为什么有的时候又能看到,有时候又不能看到呢?因为公司电脑配置配置要差一些,程序也较多,在公司电脑上运行这段代码时一般两三次可以看到一次finalize()方法被调用一次,在家里电脑上运行时,要运行七八次甚至十几次才能看到一次,是不是也和内存有关呢?我跟了一下任务管理器,没有发现什么明显的差别
esse88 2013-02-26
  • 打赏
  • 举报
回复
引用 1 楼 nmyangym 的回复:
finalize()是对象的方法,在对象变成垃圾后,销毁前执行。与System,gc()没有关系。
我在System.gc()后面加了一条输出语句,证明gc()方法每次被执行时都会调有finalize()方法.只是如果不在System.gc()后加输出语句时,gc()方法不一定被调用,加了输出语句后,gc()方法每次都会被调用。
oZouBianBian 2013-02-26
  • 打赏
  • 举报
回复
首先: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();
        }
}
abc41106 2013-02-26
  • 打赏
  • 举报
回复
个人理解,不保证正确: 可能是主线程先执行完了,导致看不到打印结果 可以在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()
nmyangym 2013-02-26
  • 打赏
  • 举报
回复
楼主可以产生大量对象,不用System.gc(),会看到finalize()方法也运行。
nmyangym 2013-02-26
  • 打赏
  • 举报
回复
finalize()是对象的方法,在对象变成垃圾后,销毁前执行。与System,gc()没有关系。
biubiubiu蘼 2013-02-26
  • 打赏
  • 举报
回复
这和内存的使用情况有关,很难准确控制。 一般E区、S0区、S1区这三个新区堆以O区这个持久对象区及任意一个达到100%会触发YGC,而P区满了会触发FGC。 所以被调用有三种情况 1. 对象失效后,被立刻回收,此时finalize方法被调用。 2. 在E、S0、S1或者O区中的时候,所处堆区达到100%,该区已经失效的所有对象被回收,会触发finalize方法。 3. P区达到100%,jvm中断当前所有进程,回收所有已经失效的对象,触发finalize方法。
l6801567 2013-02-26
  • 打赏
  • 举报
回复
引用 6 楼 rumlee 的回复:
觉得java就不应该设计有finalize这个方法。
finalize 是java调用本地程序的时候,比如C++,要释放资源的代码放finalize里面
strivehard 2013-02-26
  • 打赏
  • 举报
回复
我给你详细讲解下吧,,,首先system.gc调用后不是马上执行,,, 咱们用的虚拟机一般都是sun的hotspot,以下描述都是针对hotspot虚拟机,当然其他虚拟机也差不多, ,,他是根据跟搜索算法判断哪些垃圾需要回收 GCROOT就是跟,,垃圾回收又分为新生代和老生代,你刚new的对象,占用的内存也不会超过 直接进入老生代的标准,,因为可以存活下来的对象很少,,,所以新生代采用复制的算法,, 如果你的对象实例没有到达这个跟的引用链,,那么就会被标记为要回收的对象,新生代的内存 模型分为eden space和s0以及s1,,被标记为要清除的对象后,会进行筛选,如果这个对象没被调用过 finalize方法并且重写了finalize方法,,那么就会把这个对象加入一个叫F-queue的队列中,然后 虚拟机会启动一个优先级较低的finalizer线程去执行这个对象的finalize方法,如果在这些方法结束之前 这个对象又有了一个引用链到达gc root 那么 这个对象这次就是自救成功了, 垃圾收集器不会手机他,, 当然同一个对象实例的finalize方法只会被调用一次,也就是说只有一次自救机会。所以只有第一次收集 才会输出
rumlee 2013-02-26
  • 打赏
  • 举报
回复
觉得java就不应该设计有finalize这个方法。
sffx123 2013-02-26
  • 打赏
  • 举报
回复
避免使用终结函数,该方法不能保证一定执行,并且依赖JVM的具体实现,有可能根本不会被执行,详情请见effective java

62,614

社区成员

发帖
与我相关
我的任务
社区描述
Java 2 Standard Edition
社区管理员
  • Java SE
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧