Java強引用、軟引用、弱引用和虛引用分別是什麼?

在Java語言中,除了基本數據類型外,其他的都是指向各類對象的對象引用

Java中根據其生命週期的長短,將引用分爲以下4類:強引用、軟引用、弱引用和虛引用

下面分別闡述一下各引用的特點含義

 

一、強引用

特點:我們平常典型編碼Object obj = new Object()中的obj就是強引用。

通過關鍵字new創建的對象所關聯的引用就是強引用。 當JVM內存空間不足,JVM寧願拋出(OOM)OutOfMemoryError運行時錯誤,使程序異常終止,也不會靠隨意回收具有強引用的“存活”對象來解決內存不足的問題。因此強引用是造成java內存泄漏的主要原因之一。

對於一個普通的對象,如果沒有其他的引用關係,只要超過了引用的作用域或者顯式地將相 應(強)引用賦值爲 null,就是可以被垃圾收集的了,具體回收時機還是要看垃圾收集策略。

 


二、軟引用

特點:軟引用通過java.lang.SoftReference類實現。

軟引用的生命週期比強引用短一些。只有當 JVM 認爲內存不足時,纔會去試圖回收軟引用指向的對象:即JVM 會確保在拋出 OutOfMemoryError 之前,清理軟引用指向的對象。軟引用可以和一個引用隊列(ReferenceQueue)聯合使用,如果軟引用所引用的對象被垃圾回收器回收,Java虛擬機就會把這個軟引用加入到與之關聯的引用隊列中。後續,我們可以調用ReferenceQueue的poll()方法來檢查是否有它所關心的對象被回收。如果隊列爲空,將返回一個null,否則該方法返回隊列中前面的一個Reference對象。

應用場景:

軟引用通常用來實現內存敏感的緩存。如果還有空閒內存,就可以暫時保留緩存,當內存不足時清理掉,這樣就保證了使用緩存的同時,不會耗盡內存。

代碼驗證:

當內存足夠時,軟引用並不會被回收

public class SoftReferenceDemo {
    public static void main(String[] args) {
        Object obj = new Object();
        SoftReference<Object> softReference = new SoftReference<>(obj);
        obj = null;

        try {
            // 分配 50 M
            byte[] bytes = new byte[50 * 1024 * 1024];
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            System.out.println("軟引用:" + softReference.get());
        }

    }
}

運行結果:

 

現在設置 JVM 參數爲: -Xms10m -Xmx10m -XX:+PrintGCDetails

發現當內存不夠的時候就會被回收。

運行結果:

D:\java1.8\jdk\bin\java.exe -Xms10m -Xmx10m -XX:+PrintGCDetails "-javaagent:F:\software\Software\IntelliJ IDEA 2018.3.1\lib\idea_rt.jar=58082:F:\software\Software\IntelliJ IDEA 2018.3.1\bin" -Dfile.encoding=GBK -classpath D:\java1.8\jdk\jre\lib\charsets.jar;D:\java1.8\jdk\jre\lib\deploy.jar;D:\java1.8\jdk\jre\lib\ext\access-bridge-64.jar;D:\java1.8\jdk\jre\lib\ext\cldrdata.jar;D:\java1.8\jdk\jre\lib\ext\dnsns.jar;D:\java1.8\jdk\jre\lib\ext\jaccess.jar;D:\java1.8\jdk\jre\lib\ext\jfxrt.jar;D:\java1.8\jdk\jre\lib\ext\localedata.jar;D:\java1.8\jdk\jre\lib\ext\nashorn.jar;D:\java1.8\jdk\jre\lib\ext\sunec.jar;D:\java1.8\jdk\jre\lib\ext\sunjce_provider.jar;D:\java1.8\jdk\jre\lib\ext\sunmscapi.jar;D:\java1.8\jdk\jre\lib\ext\sunpkcs11.jar;D:\java1.8\jdk\jre\lib\ext\zipfs.jar;D:\java1.8\jdk\jre\lib\javaws.jar;D:\java1.8\jdk\jre\lib\jce.jar;D:\java1.8\jdk\jre\lib\jfr.jar;D:\java1.8\jdk\jre\lib\jfxswt.jar;D:\java1.8\jdk\jre\lib\jsse.jar;D:\java1.8\jdk\jre\lib\management-agent.jar;D:\java1.8\jdk\jre\lib\plugin.jar;D:\java1.8\jdk\jre\lib\resources.jar;D:\java1.8\jdk\jre\lib\rt.jar;D:\我的程序人生\java\IDEA\acmPractice\out\production\acmPractice com.jvm.test.SoftReferenceDemo
[GC (Allocation Failure) [PSYoungGen: 1549K->488K(2560K)] 1549K->640K(9728K), 0.0394722 secs] [Times: user=0.00 sys=0.00, real=0.05 secs] 
[GC (Allocation Failure) [PSYoungGen: 488K->488K(2560K)] 640K->676K(9728K), 0.0005820 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 
[Full GC (Allocation Failure) [PSYoungGen: 488K->0K(2560K)] [ParOldGen: 188K->585K(7168K)] 676K->585K(9728K), [Metaspace: 3074K->3074K(1056768K)], 0.0058523 secs] [Times: user=0.00 sys=0.00, real=0.01 secs] 
[GC (Allocation Failure) [PSYoungGen: 0K->0K(2560K)] 585K->585K(9728K), 0.0002133 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 
[Full GC (Allocation Failure) [PSYoungGen: 0K->0K(2560K)] [ParOldGen: 585K->568K(7168K)] 585K->568K(9728K), [Metaspace: 3074K->3074K(1056768K)], 0.0058563 secs] [Times: user=0.00 sys=0.00, real=0.01 secs] 
軟引用是否被回收:null
Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
	at com.jvm.test.SoftReferenceDemo.main(SoftReferenceDemo.java:19)
Heap
 PSYoungGen      total 2560K, used 109K [0x00000000ffd00000, 0x0000000100000000, 0x0000000100000000)
  eden space 2048K, 5% used [0x00000000ffd00000,0x00000000ffd1b628,0x00000000fff00000)
  from space 512K, 0% used [0x00000000fff00000,0x00000000fff00000,0x00000000fff80000)
  to   space 512K, 0% used [0x00000000fff80000,0x00000000fff80000,0x0000000100000000)
 ParOldGen       total 7168K, used 568K [0x00000000ff600000, 0x00000000ffd00000, 0x00000000ffd00000)
  object space 7168K, 7% used [0x00000000ff600000,0x00000000ff68e068,0x00000000ffd00000)
 Metaspace       used 3159K, capacity 4496K, committed 4864K, reserved 1056768K
  class space    used 346K, capacity 388K, committed 512K, reserved 1048576K

Process finished with exit code 1

 


三、弱引用

特點:弱引用通過WeakReference類實現。

弱引用的生命週期比軟引用短。在垃圾回收器線程掃描它所管轄的內存區域的過程中,一旦發現了具有弱引用的對象,不管當前內存空間足夠與否,都會回收它的內存。由於垃圾回收器是一個優先級很低的線程,因此不一定會很快回收弱引用的對象。弱引用可以和一個引用隊列(ReferenceQueue)聯合使用,如果弱引用所引用的對象被垃圾回收,Java虛擬機就會把這個弱引用加入到與之關聯的引用隊列中。

應用場景:弱應用同樣可用於內存敏感的緩存。

 

代碼驗證:

public class WeakReferenceDemo {
    public static void main(String[] args) {
        Object obj = new Object();
        //弱引用
        WeakReference<Object> weakReference = new WeakReference<>(obj);
        System.out.println(obj);
        System.out.println(weakReference.get());

        obj = null;
        System.gc();
        System.out.println("GC之後的結果....");

        System.out.println(obj);
        System.out.println(weakReference.get());
    }
}

運行結果:

D:\java1.8\jdk\bin\java.exe "-javaagent:F:\software\Software\IntelliJ IDEA 2018.3.1\lib\idea_rt.jar=58138:F:\software\Software\IntelliJ IDEA 2018.3.1\bin" -Dfile.encoding=GBK -classpath D:\java1.8\jdk\jre\lib\charsets.jar;D:\java1.8\jdk\jre\lib\deploy.jar;D:\java1.8\jdk\jre\lib\ext\access-bridge-64.jar;D:\java1.8\jdk\jre\lib\ext\cldrdata.jar;D:\java1.8\jdk\jre\lib\ext\dnsns.jar;D:\java1.8\jdk\jre\lib\ext\jaccess.jar;D:\java1.8\jdk\jre\lib\ext\jfxrt.jar;D:\java1.8\jdk\jre\lib\ext\localedata.jar;D:\java1.8\jdk\jre\lib\ext\nashorn.jar;D:\java1.8\jdk\jre\lib\ext\sunec.jar;D:\java1.8\jdk\jre\lib\ext\sunjce_provider.jar;D:\java1.8\jdk\jre\lib\ext\sunmscapi.jar;D:\java1.8\jdk\jre\lib\ext\sunpkcs11.jar;D:\java1.8\jdk\jre\lib\ext\zipfs.jar;D:\java1.8\jdk\jre\lib\javaws.jar;D:\java1.8\jdk\jre\lib\jce.jar;D:\java1.8\jdk\jre\lib\jfr.jar;D:\java1.8\jdk\jre\lib\jfxswt.jar;D:\java1.8\jdk\jre\lib\jsse.jar;D:\java1.8\jdk\jre\lib\management-agent.jar;D:\java1.8\jdk\jre\lib\plugin.jar;D:\java1.8\jdk\jre\lib\resources.jar;D:\java1.8\jdk\jre\lib\rt.jar;D:\我的程序人生\java\IDEA\acmPractice\out\production\acmPractice com.jvm.test.WeakReferenceDemo
java.lang.Object@1b6d3586
java.lang.Object@1b6d3586
GC之後的結果....
null
null

Process finished with exit code 0

 

值得注意的是String name = "cuzz" 這種會放入永久代,以及 Integer age = 1 在 int 中 -128 到 127 會被緩存,所以是強引用,然後 GC 也不會被回收。


 

四、虛引用

特點:虛引用也叫幻象引用,通過PhantomReference類來實現。

無法通過虛引用訪問對象的任何屬性或函數。幻象引用僅僅是提供了一種確保對象被 finalize 以後,做某些事情的機制。如果一個對象僅持有虛引用,那麼它就和沒有任何引用一樣,在任何時候都可能被垃圾回收器回收。虛引用必須和引用隊列 (ReferenceQueue)聯合使用。當垃圾回收器準備回收一個對象時,如果發現它還有虛引用,就會在回收對象的內存之前,把這個虛引用加入到與之關聯的引用隊列中。

ReferenceQueue queue = new ReferenceQueue ();

PhantomReference pr = new PhantomReference (object, queue);

程序可以通過判斷引用隊列中是否已經加入了虛引用,來了解被引用的對象是否將要被垃圾回收。如果程序發現某個虛引用已經被加入到引用隊列,那麼就可以在所引用的對象的內存被回收之前採取一些程序行動。

 

應用場景:可用來跟蹤對象被垃圾回收器回收的活動,當一個虛引用關聯的對象被垃圾收集器回收之前會收到一條系統通知。

 

總結:

1、強引用是不會被垃圾器隨意回收的,但也是造成java內存泄漏的主要原因之一。

2、軟引用使用過java.lang.SoftReference類實現。當JVM內存不足時,便會回收軟引用所引用的對象。

3、弱引用是通過WeakReference類實現。垃圾器線程回收時,一定會把弱引用給回收掉。

4、虛引用也叫幻象引用,通過PhantomReference類來實現。若一個對象僅持有虛引用,那麼它就和沒有任何引用一樣,在任何  時候都可能被垃圾回收器回收

 

每日一言:

In the contemporary world, It is of great significance for youngsters to learn Computer software well.

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章