java中有哪幾種引用?它們的含義和區別是什麼

weixin_34208283發表於2018-10-03

在jdk1.2之前,java中引用的定義:如果引用型別的資料型別中儲存的數值代表的是一塊記憶體的起始地址,就稱這塊記憶體代表一個引用。在jdk1.2之後,java引入了4種物件引用型別,級別由高到低分別是:強引用、軟引用、弱引用和虛引用。

為什麼需要不同的引用

對於需要長期執行的應用程式來說,如果無用的物件所佔的記憶體空間無法及時釋放的話,那麼在一個區域性的時間段裡就會形成事實上的記憶體洩露,如果要及時地釋放記憶體,在java中最穩妥的方式就是在使用完物件過後 立即執行“object = null”,當然這這是理想狀態。

通過這4種引用型別 強行呼叫垃圾回收方法 System.gc() 來解決記憶體洩露的問題,不同的引用方式會有不同的作用,下面我們來一一講解。

  • 強引用(StrongReference):直接引用物件,記憶體不足時也不會回收
  • 軟引用(SoftReference):記憶體不足時,回收引用相關聯的物件
  • 弱引用 (WeakReference):無論記憶體是否充足,都回收引用相關聯的物件
  • 虛引用(PhantomReference):任何時候都可以被垃圾回收器回收
強引用

強引用是日常程式設計中最常用的一種引用型別,它的特點是隻要引用存在,就永遠不會呼叫垃圾回收方法對其進行釋放記憶體,java虛擬機器寧可出現OutOfMemoryError錯誤停止執行,也會儲存記憶體空間。只用當這個物件的引用被釋放掉,物件才會被釋放。
正是因為強引用具備這樣的特點,所以我們的開發原則是儘量少例項化物件。
強引用是造成java記憶體洩露的主要原因之一。

軟引用

軟引用是指非必須引用,在記憶體足夠時是不會對其進行回收,而在記憶體不足的時候垃圾回收器會將其回收並釋放記憶體。java中軟引用對應著SoftReference類,如果想要一個物件被軟引用,只需要將其作為引數傳入SoftReference類的構造方法中就行了。

軟引用主要用於使用者實現類似快取的功能,在記憶體足夠的情況下直接通過軟引用取值,無需從繁忙的真實來源查詢資料,提升速度;當記憶體不足時,自動刪除這部分快取資料,從真實來源查詢這些資料。軟引用可以和一個引用佇列(ReferenceQueue)聯合使用,如果軟引用所引用的物件被垃圾回收器回收,java虛擬機器就會把這個軟引用加入到與之關聯的佇列引用中。

弱引用

弱引用相對於軟引用,被弱引用的物件擁有更短的記憶體時間(生命週期)。垃圾回收器一旦發現了被弱引用的物件,就會回收它的記憶體,不管當前記憶體空間是不是足夠。不過,由於垃圾回收器是一個優先順序很低的執行緒,因此不一定很快發現那些弱引用的物件。對應java中的WeakReference類,使用方法與軟引用基本相同,弱引用可以和一個引用佇列(ReferenceQueue)聯合使用,如果弱引用所引用的物件被垃圾回收器回收,java虛擬機器就會把這個軟引用加入到與之關聯的佇列引用中。

弱引用主要應用於監控物件是否被垃圾回收器標記為即將回收的垃圾,可以通過弱引用的isEnQueued方法返回物件是否被垃圾回收器標記

虛引用

顧名思義:形同虛設,虛引用並不會決定物件的生命週期,如果一個物件僅有虛引用,那麼它就和沒有任何引用一樣,在任何時候都可能被垃圾回收器回收。程式也不能通過虛引用訪問被引用的物件。
虛引用主要用來跟蹤垃圾回收器回收的活動,虛引用與弱應用,軟引用的區別在於:虛引用必須和引用佇列(ReferenceQueue)聯合使用,當垃圾回收器準備回收一個物件時,如果發現它還有虛引用,就會在回收物件記憶體之前,把這個虛引用加入到與之關聯的佇列中。

程式碼

/**
 * 強引用
 */
public static void main(String[] args) {

    Object object = new Object();//強引用

    Object ref = object;//引用傳遞

    System.out.println(object);

    boolean equals = object.equals(new Object()); //可直接通過obj取得對應的物件
    System.out.println(equals);

    object = null;//斷開引用與物件的連結
    System.gc();


    System.out.println(object);
    System.out.println(ref);
}

/**
 * 弱引用
 */
public static void main(String[] args) {
    Object object = new Object();

    SoftReference<Object> reference = new SoftReference<Object>(object);

    object = null;

    System.out.println(reference.get());

//        System.gc();//對比弱引用
//        System.out.println(reference.get());

    final String str = "1111111111111111111111111111111111111111";//用於佔用記憶體,建立一個final且字元較多的字串
    String string = "";

    try {
        for (int i = 0; i < Integer.MAX_VALUE; i++) {
            string = string + str;
            string.intern();//該方法返回一個規範化表示的string物件。一個字串常量池,初始化為空,且被String類私有地維護。
            // 當intern()被呼叫時,如果常量池中存在和該String物件equal的物件(由equals方法決定),則返回常量池中已有的String物件,若不存在,則將該物件加入常量池,並返回該物件的引用。
        }
    } catch (Throwable throwable) {
        System.out.println("----------errot--");
    }

    System.out.println(reference.get());//結果:null 切勿多次執行結果,否則電腦記憶體會約佔越多,變卡
}

/**
 * 弱引用
 */
public static void main(String[] args) {

    Object object = new Object();

    WeakReference<Object> reference = new WeakReference<Object>(object);

    object = null;

    System.out.println(reference.get());//結果:java.lang.Object@610455d6

    System.gc();

    System.out.println(reference.get());//結果:null
}

/**
 * 虛引用
 */
public static void main(String[] args) {

    ReferenceQueue<String> queue = new ReferenceQueue<>();

    String string = new String("hello");

    PhantomReference<String> reference = new PhantomReference<String>(string,queue);

    System.out.println(reference.get());

}

相關文章