1. 程式人生 > >finalize()與System.gc()

finalize()與System.gc()

GC的特殊情況與finalize()的“假定”原理
GC負責回收無用物件佔據的記憶體資源。但也有特殊情況:假定你的物件(並非使用new)獲得了一塊“特殊”的記憶體區域,由於垃圾回收器只知道釋放那些經由new分配的記憶體,所以它不知道該如何釋放該物件的這塊“特殊”記憶體。為了應對這種情況,Java允許在類中定義一個名為finalize()的方法。它的工作原理“假定”是這樣的:一旦GC準備好釋放物件佔用的儲存空間,將首先呼叫其finalize()方法,並且在下一次垃圾回收動作發生時,才會真正回收物件佔用的記憶體。
finalize()的作用?

1.釋放“特殊”記憶體

gc只能清除在堆上分配的記憶體,而不能清除在棧上分配的記憶體,當使用JNI技術令Java呼叫C或C++程式碼時,可能會在棧上分配記憶體(例如Java呼叫C程式,C使用malloc分配記憶體),這時要想釋放儲存空間,gc起不到任何作用,除非呼叫C的free函式,否則儲存空間將得不到釋放,從而造成記憶體洩露,所以需要在finalize()中用本地方法呼叫它。

2.驗證終結條件(可能的使用方式)

例如,要是物件代表了一個開啟的檔案,在物件被回收前程式設計師應該關閉這個檔案。只要物件中存在沒有被適當清理的部分,程式就存在很隱晦的缺陷,finalize()可以用來最終發現這種情況--雖然它並不總會被呼叫。

public class Book {
	boolean checkedOut = false;
	Book(boolean checkOut){
		checkedOut = checkOut;
	}
	void checkIn(){
		checkedOut = false;
	}
	protected void finalize(){
		if(checkedOut)
			System.out.println("finalize() called!");
	}
	public static void main(String[] args) {
		for(int i = 0; i < 100; i++){
			Book novel = new Book(true);
			novel.checkIn();
		}
		new Book(true);
		System.gc();
	}
}
/*驗證結果是大多數情況下finalize()會被呼叫*/
Output: finalize() called!<span style="font-family: Arial, Helvetica, sans-serif; background-color: rgb(255, 255, 255);">	</span>
finalize()何時被呼叫?

1.所有物件被GC時自動呼叫

2.程式退出時為每一個物件呼叫finalize()方法

3.在程式中呼叫System.gc()(但也只是建議JVM執行而不一定馬上執行),直到1

此外,當某個物件被系統收集為無用資訊的時候,finalize()將被自動呼叫,但是jvm不保證finalize()一定被呼叫,也就是說,finalize()的呼叫是不確定的,這也就是為什麼sun不提倡使用finalize()的原因.。

System.gc()的作用?

當顯示地呼叫System.gc()時,System.gc()會建議JVM進行GC,但決定權還是留在JVM手裡,由它決定是否回收垃圾。

public class Test {

	protected void finalize(){
		System.out.println("finalize() called!");
	}
	public static void main(String[] args) {
		new Test();
		System.gc();
	}
}
/*驗證結果是大多數情況下finalize()會被呼叫*/
Output: finalize() called!