垃圾回收與對象的引用
阿新 • • 發佈:2018-05-16
finalize 物理 tst 測試 div 是我 出現異常 AI .net
垃圾回收
當程序創建對象、數組等引用類型實體時,系統就會在對內存中為之分配一塊內存區,對象就保存在這塊內存區中,當這塊內存不再被任何引用變量引用時,這塊內存就變成垃圾,等待垃圾回收機制進行回收。
垃圾回收機制具有如下特點:
- 垃圾回收機制只負責回收堆內存中的對象,不會回收任何物理資源。
- 程序無法精確控制垃圾回收的運行,垃圾回收會在合適的時候進行。當對象永久性地失去引用後,系統就會在合適的時候回收它所占的內存。
- 在垃圾回收機制回收任何對象之前,總會調用它的finalize()方法,可以重寫該方法,讓一個引用變量重新引用該對象,從而導致垃圾回收機制取消回收。
對象在內存中的狀態
- 可達狀態:當一個對象創建後,若有變量引用它,則這個對象在程序中處於可達狀態。
- 可恢復狀態:如果程序中某個對象不再有任何引用變量應用它,且該對象還沒有調用finalize()方法。在這種狀態下,系統的垃圾回收機制準備回收該對象所引用的內存,在回收該對象之前,系統會調用所有可恢復狀態對象的finalize()方法進行資源清理。
- 不可達狀態:當對象與所有引用變量的關聯都被切斷,且系統已經調用所有對象的finalize()方法後依然沒有使該對象變為可達狀態,那麽該對象將永久地失去應用,變成不可達狀態,系統會回收處於改狀態的資源。
強制垃圾回收
當一個對象失去引用後,系統何時調用它的finalize()方法對它進行資源清理,對於程序是不可控的。
程序無法精確控制Java垃圾回收的時機,但依然可以強制系統進行垃圾回收-這種強制只是通知系統進行垃圾回收,但系統是否進行垃圾回收依然不確定。大部分時候,程序強制系統垃圾回收後總會有一些效果。強制系統垃圾回收有如下兩種方式:
System.gc()
Runtime.getRuntime().gc()
finalize方法
Object類的finalize()方法沒有做任何事情,子類可以選擇重寫,如下:
protected void finalize() throws Throwable { }
下面我重寫finalize()方法,使一個沒被應用的對象重新被引用,變成可達狀態。
/**
* Created by SqMax on 2018/5/12.
*/
public class FinalizeTest {
private static FinalizeTest ft;
public void info (){
System.out.println("測試方法");
}
@Override
protected void finalize() throws Throwable {
System.out.println("讓變量引用該對象,使其變為可達狀態");
ft=this;
}
public static void main(String[] args) {
// 該對象沒有任何引用變量引用,處於可恢復狀態
new FinalizeTest();
System.gc();
// Runtime.getRuntime().gc();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
ft.info();
}
}
上面我們調用System.gc()方法後,還讓當前線程休眠了1秒鐘,因為垃圾回收機制也是一個線程,我們通知垃圾回收機制回收垃圾後,垃圾回收線程還是和main線程爭奪CPU資源,所以讓main線程休眠,這樣垃圾回收線程就會通知沒被引用的對象調用finalize()方法,是我們的ft變量引用這個對象。
執行結果如下:
讓變量引用該對象,使其變為可達狀態
測試方法
finalize方法有如下4個特點:
- 永遠不要調用某個對象的finalize()方法,該方法應交給垃圾回收機制調用。
- finalize()方法何時調用具有不確定性,不要把finalize()方法當成一定被執行的方法。
- 當JVM執行finalize()方法出現異常時,垃圾回收機制不會報告異常,程序繼續執行。
- 垃圾回收機制是一個後臺線程,finalize()方法也是在這個後臺線程裏調用的,主線程執行完後,這個後臺線程也結束,如下:
public class FinalizeTest {
private static FinalizeTest ft;
public void info(){
System.out.println("測試方法");
}
@Override
protected void finalize() throws Throwable {
System.out.println("正在進行垃圾回收....");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("讓變量引用該對象,使其變為可達狀態");
ft=this;
}
public static void main(String[] args) {
// 該對象沒有任何引用變量引用,處於可恢復狀態
new FinalizeTest();
System.gc();
}
}
執行結果如下:
正在進行垃圾回收....
可以看到finalize()方法還沒運行完,程序就結束了。
由於finalize()方法並不一定會被執行,而且不一定會執行完,因此如果清理某個類裏打開的資源,則不要放在finalize()方法裏進行清理,而應該在finally異常處理的finally塊裏清理。
對象的軟、弱、和虛引用
目前還沒有在項目中遇到該知識點的應用,以後遇到在補充.........
垃圾回收與對象的引用