強軟弱虛
java中的數據被類型分為了兩類,它們分別是基本類型和引用類型。一般我們new出來的對象都屬於引用類型的范疇。我們知道java是有垃圾回收機制的一種語言,根據垃圾回收時的策略,java將對於堆對象的引用又進行了細分,引用被分為了強引用,軟引用,弱引用和虛引用。
強引用
強引用又稱普通引用,它是最常見的一種引用類型,一般我們通過new
關鍵字創建對象時,變量對於堆對象的引用就是強引用。
強引用的特點:
- 如果堆中的一個對象被強引用指向,那么這個變量將不會被GC回收。
- 在堆內存不夠用的情況下,被強引用指向的對象也不會被回收。(寧可拋出OOM異常)
- 被強引用指向的對象,只有在引用消失后才會被GC回收。
測試代碼-1:
1 /* 這個類用於申請堆內存 */ 2 public class Memory { 3 private byte[] alloc; 4 5 public Memory(int size) { this.alloc = new byte[size]; } 6 7 @Override 8 protected void finalize() throws Throwable { 9 super.finalize(); 10 System.out.println("被GC回收"); 11 } 12 }
1 public class Normal { 2 public static void main(String[] args) throws InterruptedException { 3 4 /* 棧變量m對new出來的Memory對象的引用為強引用 */ 5 Memory m = new Memory(1024 * 1024 * 20); 6 7 /* 現在堆中的對象沒有引用指向它,它要被GC回收 */ 8 m = null; 9 10 System.gc(); /* 顯式GC */ 11 12 /* 13 * 當我們啟動java程序時,默認會有兩個線程,一個是我們的主線程,另一個便是GC線程。 14 * 通常GC線程的優先級比較低,並且GC線程默認為守護線程,即它會在主線程退出的同 15 * 時退出。 16 * 17 * 為了觀察到GC的效果,我們讓主線程休眠1s 18 */ 19 Thread.sleep(1000); 20 } 21 22 }
測試結果-1:
測試代碼-2
1 public class Normal { 2 3 public static void main(String[] args) throws InterruptedException { 4 5 /* 我們設定JVM參數,設置堆內存大小為25MB */ 6 7 8 /* 棧變量m1對new出來的Memory對象的引用為強引用 */ 9 10 /* 申請了20MB的內存,實際會大於20MB,因為我們的byte[]被Memory對象wrapper */ 11 Memory m1 = new Memory(1024 * 1024 * 20); 12 13 System.gc(); 14 Thread.sleep(1000); 15 16 /* 再申請10MB堆內存 */ 17 Memory m2 = new Memory(1024 * 1024 * 10); 18 } 19 20 }
測試結果-2
軟引用
軟引用的創建需要借助jdk中java.lang.ref.SoftReference
這個類來創建。也就是說,我們的變量是先引用到SoftReference這個對象,SofReference這個對象再去引用我們想要設置為軟引用的對象。
軟引用的特點
- 當堆內存夠用時,被軟引用指向的對象不會被GC回收。
- 當堆內存不夠用時,被軟引用指向的對象自動的被GC回收。
測試代碼-3
1 public class Soft_Ref { 2 3 public static void main(String[] args) throws InterruptedException { 4 /* 堆內存大小為50MB */ 5 /* 申請30MB */ 6 SoftReference<Memory> m1 = new SoftReference<>(new Memory(1024 * 1024 * 30)); 7 8 System.gc(); /* 顯示調用GC */ 9 10 /* 此時內存夠用,所以結果可以預見性的為GC不會回收被軟引用指向的對象 */ 11 12 Thread.sleep(1000); 13 } 14 }
測試結果-3
測試代碼-4
1 public class Soft_Ref { 2 public static void main(String[] args) throws InterruptedException { 3 4 /* 堆內存大小為50MB */ 5 6 /* 申請30MB */ 7 SoftReference<Memory> m1 = new SoftReference<>(new Memory(1024 * 1024 * 30)); 8 9 10 /* 申請20MB */ 11 for (int i = 0; i < 20; ++i) { 12 System.out.println("[time] => " + System.currentTimeMillis()); 13 SoftReference<Memory> ma = new SoftReference<>(new Memory(1024 * 1024)); 14 Thread.sleep(200); 15 } 16 } 17 }
測試結果-4
從測試結果可以看出,當內存不夠用或者將要不夠用時,會觸發GC,GC會自動的回收那些軟引用指向對象。
一定要注意,軟引用指向對象的回收是在觸發GC的條件下才會被回收,如果內存夠用,就算顯式的調用GC,軟引用指向的對象也不會被回收。
弱引用
弱引用的創建方式與軟引用類似,需要借助於jdk中java.lang.ref.WeakReference
類去創建。
弱引用的特點:
- 不管什么情況,遇到GC就會回收被弱引用指向的對象。
測試代碼-5
1 public class Weak_Ref { 2 3 public static void main(String[] args) throws InterruptedException { 4 /* 堆內存沒有設置大小,為默認狀態 */ 5 WeakReference<Memory> m = new WeakReference<>(new Memory(1024 * 1024 * 10)); 6 System.gc(); /* 調用GC */ 7 Thread.sleep(1000); 8 } 9 }
測試結果-5

虛引用
虛引用是一種十分特殊的引用,它主要用在堆外內存的管理,虛引用可以指向堆中的對象,但是沒有實際的意義。
虛引用的特點:
- 無法獲取虛引用指向的對象的值。
- 虛引用在被GC回收時會有通知。
- 虛引用在遇到GC時,不管是否還有對象引用它,它都會被GC回收。
測試代碼-6
1 public class Phantom_Ref { 2 static final ArrayList<byte[]> LIST = new ArrayList<>(); 3 4 static final ReferenceQueue<Memory> QUEUE = new ReferenceQueue<>(); 5 6 public static void main(String[] args) throws InterruptedException { 7 8 PhantomReference<Memory> m = new PhantomReference<>(new Memory(1024 * 1024 * 10), QUEUE); 9 new Thread(()->{ 10 while (true) { 11 LIST.add(new byte[1024 * 1024 ]); 12 13 try { 14 Thread.sleep(1000); 15 } catch (InterruptedException e) { 16 e.printStackTrace(); 17 Thread.currentThread().interrupt(); 18 } 19 System.out.println(m.get()); /* 虛引用指向的值永遠無法被獲取 */ 20 } 21 }).start(); 22 23 new Thread(()->{ 24 while (true) { 25 Reference<? extends Memory> poll = QUEUE.poll(); 26 if (poll != null) { 27 /* 虛引用在對象回收時,會進行通知 */ 28 System.out.println("有虛引用被GC回收了-" + poll); 29 break; 30 } 31 } 32 }).start(); 33 } 34 }
測試結果-6
以上就是小編整理的Java的四種引用,只是個人的一些理解看法,有哪里不准確的地方,還請大家多多指出,小編和大家共同進步!!!
喜歡文章請多多點贊評論轉發,關注小編,你們的支持就是小編創作的無限動力!!!!!