在JAVA垃圾回收机制中,怎么解释一个对象的finalize只可能运行一次? 求详解~

那如果一开始把对象变为不可达,然后用system.gc(),并且在finalize里面有一条语句,让对象又变成可达对象呢?

谢谢大家的回答。我还有一点不明白。
一个对象的生命周期中FINALIZE方法最多被执行一次。 这句话怎么解释?生命周期具体指的是什么?

final—修饰符(关键字)如果一个类被声明为final,意味着它不能再派生出新的子类,不能作为父类被继承。因此一个类不能既被声明为 abstract的,又被声明为final的。将变量或方法声明为final,可以保证它们在使用中不被改变。被声明为final的变量必须在声明时给定初值,而在以后的引用中只能读取,不可修改。被声明为final的方法也同样只能使用,不能重载。
finally—再异常处理时提供 finally 块来执行任何清除操作。如果抛出一个异常,那么相匹配的 catch 子句就会执行,然后控制就会进入 finally 块(如果有的话)。
finalize—方法名。Java 技术允许使用 finalize() 方法在垃圾收集器将对象从内存中清除出去之前做必要的清理工作。这个方法是由垃圾收集器在确定这个对象没有被引用时对这个对象调用的。它是在 Object 类中定义的,因此所有的类都继承了它。子类覆盖 finalize() 方法以整理系统资源或者执行其他清理工作。finalize() 方法是在垃圾收集器删除对象之前对这个对象调用的。

我在thinking in java中看见以下一段代码。

//:Garbage.java
//Demonstration of the garbage
//collector and finalization

class Chair {
static boolean gcrun=false;
static boolean f=false;
static int created=0;
static int finalized=0;
int i;
Chair(){
i=++created;
if(created==47)
System.out.println("Created 47");
}
protected void finalize(){
if(!gcrun){
gcrun=true;
System.out.println(
"Beginning to finalize after"+created+
"Chairs have been created");
}
if(i==47){
System.out.println(
"Finalizing Chair #47,"+
"Setting flag to stop Chair creation");
f=true;
}
finalized++;
if(finalized>=created)
System.out.println(
"All"+finalized+"finalized");
}
}

public class Garbage{
public static void main(String[] args){
if(args.length==0){
System.out.println("Usage:\n"+
"java Garbage before\n or:\n"+
"java Garbage after");
return;
}
while(!Chair.f){
new Chair();
new String("To take up space");
}
System.out.println(
"After all chairs have been created:\n"+
"total created ="+Chair.created+
",total finalized ="+Chair.finalized);
if(args[0].equals("before")){
System.out.println("gc():");
System.gc();
System.out.println("runFinalization():");
System.runFinalization();
}
System.out.println("bye");
if(args[0].equals("after"))
System.runFinalizersOnExit(true);
}
}///:-

为什么执行java Gerbage before
以后,当所有对象创建完(比如8000个),这时只清除了2000个(不定)
应该只能创建47个对象啊

分析:
首先,在一个循环当中创建对象,并且只是创建,而不引用,也就是说这个对象会自动的被系统当作垃圾处理掉。但请注意,finalize()方法并不是立刻就会执行的,执行的时间完全由系统来决定。所以很有可能的情况是已经创建了20000个对象,才开始其中的某一个对象的清除工作(这可能和时间或者系统内容的占用有关)。看finalize()方法中的一段代码:
if (!gcrun) {
gcrun = true;
System.out.println(
"\nBeginning to finalize after" + created + "Chairs have been created\nat ");
}
就会出现这样的结果:
Beginning to finalize after 25038 Chairs have been created

这时对象的创建过程仍在继续(因为已经Finalize的对象还不满47个,Chair.f还是false)。所以Chair.created会继续增加。
直到有47个对象被清除了,Chair.f被置成true了,创建对象的循环才结束。看main方法中的一段代码:
System.out.println(
"\nAfter all chairs have been created:\n"
+ "total created ="
+ Chair.created
+ ",total finalized ="
+ Chair.finalized+"\n");
如上所说,Chair.created是不断增加的,而在这段代码执行之前,又会有N个对象被释放掉了,所以finalized也增加了。
结果可能是这样的:
total created =29096,total finalized =73

其实这一过程和你使用的JVM有很大关系,执行结果可能会很不相同。但有一点是可以肯定的,那就是我们无法确定JVM什么时候做对象的清除工作(这也是Thinking in java中这段代码的想要说明的),可能会在这个对象刚刚“无用”的时候就清除掉了,也可能滞后几秒,甚至永远不清除。

如果你的开发环境支持跟踪的话,你可以以STEP的方式运行,你会看到运行结果大不相同。给你看看我的运行结果:
Created 47
Beginning to finalize af
created
Finalizing Chair #47,Setting flag to stop Chair creation
After all chairs have been created:
total created =45993,total finalized =1800
gc():
runFinalization():
bye
All45993finalized

注意最后一行,因为人为的停顿,JVM有足够的时间将所有的对象都清除了。

结论:
不能指望finalize()方法能稳定的工作,尤其不能依靠它来做文件的关闭等操作,由于finalize()的不确定性,往往得不到你想要的结果。事实上我们只需要知道所有无用的对象,JVM会自己清除就够了。
温馨提示:内容为网友见解,仅供参考
第1个回答  2011-01-03
class Garbage{
private int num=0;
Garbage(int num)
{
this.num=num;
}
protected void finalize(){
FinalizeOnce.g2=this;
System.out.println(this);

}
public String toString()
{

return "Garbage"+num;
}

}
public class FinalizeOnce{
Garbage g1=new Garbage(1);
static Garbage g2=new Garbage(2);
static Garbage g3;
public static void main(String[] args)
{
FinalizeOnce fo=new FinalizeOnce();
fo.g1=null;
g2=null;
System.gc();
g3=g2;
System.out.println(g3+“hi");
g2=null;
g3=null;
System.gc();

}
}

用代码说话
输出结果
Garbage1
Garbage2
Garbage2hi
首先g1,g2引用赋值null后,调用了gc,执行finalize语句,
但是finalize语句里面 FinalizeOnce.g2=this;
g2的对象并没有回收。
首先打印出
Garbage1
Garbage2
接着g2赋值给g3 执行 System.out.println(g3+"hi");
打印出
Garbage2hi
不过因为这个对象finalize运行过一次了,即使再次调用gc,也不会执行finalize语句。

如果把FinalizeOnce.g2=this;
这行语句注释掉
就会打印出
Garbage1
Garbage2
nullhi
g3所指向的对象由于执行过finalize,而不会再次执行了。

如果把static Garbage g3;改成static Garbage g3=new Garbage(3);
运行结果就是:
Garbage1
Garbage2
Garbage2hi
Garbage3
因为一个对象的finalize只可能运行一次。
第2个回答  2011-01-02
俺简单解释一下吧。不是只能运行一次,而是只需要运行一次。

这是一个object的生命流程,那个中文翻译可能有点偏差:
1 Created 建立
2 In use (strongly reachable) 使用中
3 Invisible 不可视
4 Unreachable 无法使用
5 Collected 被收集
6 Finalized 已终结化
7 Deallocated 消失

一个对象object的finalize method是在第5步执行的。
这个对象要被回收了。但是在回收前,再检查一遍是否有资源还被这个对象使用,例如File I/O, Socket等等。如果有的话,就该放开这个资源。然后到第7步这个对象就要消失了。

怎么可能对已经不存在的对象再次执行finalize呢?

------------------
对于问题补充的答复。
我提供的生命流程中第6步Finalized的要求是: 当对象在执行完finalize()后, 还是不可达状态。
所以如果在finalize()中使对象object变成可达,这个对象则无法完成生命流程中的第6步。也就无法被回收了。
第3个回答  2011-01-02
这就涉及到FINALIZE方法的安全问题了。为了防止人为的在FINALIZE方法中写恶意代码,使对象不成为垃圾,阻止垃圾收集。JAVA中规定:一个对象的生命周期中FINALIZE方法最多被执行一次。
不过这“一个对象的生命周期”,到现在我还不是很了解。如何有高人知道,请指点一下。
第4个回答  2011-01-02
因为一个人只能死一次!本回答被网友采纳

...怎么解释一个对象的finalize只可能运行一次? 求详解~
首先,在一个循环当中创建对象,并且只是创建,而不引用,也就是说这个对象会自动的被系统当作垃圾处理掉。但请注意,finalize()方法并不是立刻就会执行的,执行的时间完全由系统来决定。所以很有可能的情况是已经创建了20000个对象,才开始其中的某一个对象的清除工作(这可能和时间或者系统内容的占用有...

java中finalize方法中的代码为什么不保证一定执行?
finalize方法是对象被垃圾收集器清理的时候调用的 除非你自己强制用System.gc()来调用垃圾收集器,否则你不可能知道什么时候系统会自己调用垃圾收集器 也就不可能保证会调用finalize方法

Java中的finalize详解
finalize( )里加入某种擦除功能 当 垃圾回收 发生时(不能保证一定会发生) finalize( )得到了调用 图像就会被擦除 要是 垃圾回收 没有发生 图像就会一直保留下来 也许你会发现 只要程序没有濒临存储空间用完的那一刻 对象占用的空间就总也得不到释放 如果程序执行结束 并且垃圾回收器一直都没有释放...

Java中final,finally和finalize的区别
finally 是异常处理语句结构的一部分,表示总是执行。finalize 是Object类的一个方法,在垃圾收集器执行的时候会调用被回收对象的此方法,可以覆盖此方法提供垃圾收集时的其他资源回收,例如关闭文件等 final—修饰符(关键字)如果一个类被声明为final,意味着它不能再派生出新的子类,不能作为父类被继承。

JAVA中FINALIZE用法
方法:用a1=null来说明a1指向的内存为垃圾 FINALIZE方法就会被调用了 原因: 对此问题 通过看Java编程思想,自己有以下理解 ava有自己的垃圾回收机制, 1。当对象没有用时,对象并不是立即被回收,而是当垃圾回收进程启动的时候,垃圾才会被回收,回收时会调用FINALIZE方法--另一种是调用System的gc()...

JAVA里finalize()方法是干什么用的?
在从堆中永久删除对象之前,垃圾回收器调用该对象的Finalize方法。注意,无法确切地保证垃圾回收器何时调用该方法,也无法保证调用不同对象的方法的顺序。即使一个对象包含另一个对象的引用,或者在释放一个对象很久以前就释放了另一个对象,也可能会以任意的顺序调用这两个对象的Finalize方法。如果必须保证...

java 中的finalize怎么用啊?
java的finalize的使用方式如下:1.所有对象被Garbage Collection时自动调用,比如运行System.gc()的时候.2.程序退出时为每个对象调用一次finalize方法。3.显式的调用finalize方法 除此以外,正常情况下,当某个对象被系统收集为无用信息的时候,finalize()将被自动调用,但是jvm不保证finalize()一定被调用,也就...

Java中的finalize()方法
finalize()一般是用不到的,除非JVM认为已经没有内存可以使用了,那时JVM才会消耗资源去清理垃圾,所以finalize()也不能作为通用的清理方法。而且finalize()有一个比较另类的用法,就是说finalize()并不依赖对它的直接调用,它有某些触发机制,比如说对象已经标明要被终结,这时会自动执行finalize()。并不...

JAVA中一个类的对象被垃圾回收器回收前,它的方法回自动执行吗?
ob.generator(count);} 在这里调用创建完第一个对象后,开始创建第二个对象,这个时候你第一个创建的对象就超过有效使用范围成垃圾对象了,就会自动被清理而调用第一个对象的finalize()方法了。以此类推你这个循环里建的对象都是在一创建完后立马成垃圾对象了,所以要被回收,就造成了你以为是在创建的...

java中finalize方法的问题
这是JAVA的诡异机制啊...说起来是在"被释放时"自动调用...但问题是JAVA的内存是自动管理的...所以你无法知道丫什么时候JVM才会把这个东西给释放掉...所以想用这方法做输出是不现实的...老老实实在里面把需要关的对象close一下就好了...

相似回答