1. 程式人生 > >垃圾回收與對象的引用

垃圾回收與對象的引用

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塊裏清理。

對象的軟、弱、和虛引用

目前還沒有在項目中遇到該知識點的應用,以後遇到在補充.........

垃圾回收與對象的引用