finalize()與System.gc()
阿新 • • 發佈:2018-12-26
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!