关于JAVA清理终结和垃圾回收,验证最终没有完成回收出错问题

MarkManYUN 2017-05-16 08:38:29
概念内容
垃圾回收器要回收对象的时候,首先要调用这个类的finalize方法(你可以 写程序验证这个结论),一般的纯Java编写的Class不需要重新覆盖这个方法,因为Object已经实现了一个默认的,除非我们要实现特殊的功能(这 里面涉及到很多东西,比如对象空间树等内容)。
不过用Java以外的代码编写的Class(比如JNI,C++的new方法分配的内存),垃圾回收器并不能对这些部分进行正确的回收,这时就需要我们覆盖默认的方法来实现对这部分内存的正确释放和回收(比如C++需要delete)。
总之,finalize相当于析构函数,他是垃圾回收器回收一个对象的时候第一个要调用的方法。不过由于Java的垃圾回收机制能自动为我们做这些事情,所以我们在一般情况下是不需要自己来手工释放的。

有时当撤消一个对象时,需要完成一些操作。例如,如果一个对象正在处理的是非Java 资源,如文件句柄或window 字符字体,这时你要确认在一个对象被撤消以前要保证这些资源被释放。为处理这样的状况,Java 提供了被称为收尾(finalization )的机制。使用该机制你可以定义一些特殊的操作,这些操作在一个对象将要被垃圾回收程序释放时执行。
要给一个类增加收尾(finalizer ),你只要定义finalize ( ) 方法即可。Java 回收该类的一个对象时,就会调用这个方法。在finalize ( )方法中,你要指定在一个对象被撤消前必须执行的操作。垃圾回收周期性地运行,检查对象不再被运行状态引用或间接地通过其他对象引用。就在对象被释放之 前,Java 运行系统调用该对象的finalize( ) 方法。

  finalize()方法的通用格式如下:

  protected void finalize( )
{
// finalization code here
}

  其中,关键字protected是防止在该类之外定义的代码访问finalize()标识符。该标识符和其他标识符将在第7章中解释。

  理解finalize( ) 正好在垃圾回收以前被调用非常重要。例如当一个对象超出了它的作用域时,finalize( ) 并不被调用。这意味着你不可能知道何时——甚至是否——finalize( ) 被调用。因此,你的程序应该提供其他的方法来释放由对象使用的系统资源,而不能依靠finalize( ) 来完成程序的正常操作。

  注意:如果你熟悉C++,那你知道C++允许你为一个类定义一个撤消函数(destructor ),它在对象正好出作用域之前被调用。Java不支持这个想法也不提供撤消函数。finalize() 方法只和撤消函数的功能接近。当你对Java 有丰富经验时,你将看到因为Java使用垃圾回收子系统,几乎没有必要使用撤消函数。


finalize的工作原理应该是这样的:一旦垃圾收集器准备好释放对象占用的存储空间,它首先调用finalize(),而且只有在下一次垃圾收集过程中,才会真正回收对象的内存.所以如果使用finalize(),就可以在垃圾收集期间进行一些重要的清除或清扫工作.

finalize()在什么时候被调用?
有三种情况
1.所有对象被Garbage Collection时自动调用,比如运行System.gc()的时候.
2.程序退出时为每个对象调用一次finalize方法。
3.显式的调用finalize方法

验证
public class TerminationCondition {
public static void main(String[] args) {
Book novel = new Book(true);
novel.checkIn();
new Book(true);
System.gc();// 在没有创建对象的函数中,在main()方法中由于成程序员的错误,有一本书没有嵌入,要是没有finalize()来验证终结条件,将很难发现这种缺陷。
Book novel2 = new Book(true);
System.gc();// 这里不需要使用system.gc()来终结条件,因为在这里的这个对象中已经分配了内存,所以
// 系统回收机制会自动的释放这个内存。
}
//没有释放的运行结果:The type Book is already defined(类型Book已经被定义了);
}

class Book {
boolean checkedout = false;

Book(boolean checkout) {
checkedout = checkout;
}

void checkIn() {
checkedout = false;
}

protected void finalize() {
if (checkedout) {
System.out.println("error:checked out");
}
}
}


出现问题:在跟着验证时,成功的执行了fanalize();有提示信息;但接着我尝试将fanalize()函数名进行更改后运行,然后出现错误:The type Book is already defined;对object-》进行了clean没作用,问题来了,我该怎么做才能回到一开始正规验证的样子(除开更名,重新建立类)
...全文
282 1 打赏 收藏 转发到动态 举报
写回复
用AI写文章
1 条回复
切换为时间正序
请发表友善的回复…
发表回复
MarkManYUN 2017-05-16
  • 打赏
  • 举报
回复
在更名为Book1时,能够执行
public class TerminationCondition {
	public static void main(String[] args) {
		Book1 novel = new Book1(true);
		novel.checkIn();
		new Book1(true);
		System.gc();// 在没有创建对象的函数中,在main()方法中由于成程序员的错误,有一本书没有嵌入,要是没有finalize()来验证终结条件,将很难发现这种缺陷。
		Book1 novel2 = new Book1(true);
		System.gc();// 这里不需要使用system.gc()来终结条件,因为在这里的这个对象中已经分配了内存,所以
					// 系统回收机制会自动的释放这个内存。
	}
	//没有释放的运行结果:The type Book is already defined(类型Book已经被定义了);
}

class Book1 {
	boolean checkedout = false;

	Book1(boolean checkout) {
		checkedout = checkout;
	}

	void checkIn() {
		checkedout = false;
	}

	protected void finalize() {
		if (checkedout) {
			System.out.println("error:checked out");
		}
	}
}
运行结果:error:checked out

62,621

社区成员

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

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