国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

Java中的四種引用類型:強引用、軟引用、弱引用和虛引用

makeFoxPlay / 1455人閱讀

摘要:虛引用與軟引用和弱引用的一個區別在于虛引用必須和引用隊列聯合使用。

本文已同步至個人博客liaosi"s blog

在Java中是由JVM負責內存的分配和回收,這是它的優點(簡化編程者的工作,不需要像C語言那樣去手動操作內存),但同時也是它的缺點(不夠靈活,垃圾回收對于編程者來說是不可控的)。

在JDK1.2以前,如果一個對象不被任何變量引用,則程序無法再次使用這個對象,這個對象最終會被GC(GabageCollection:垃圾回收)。但是如果之后可能還會用到這個對象,就只能去新建一個了,這其實就降低了JVM性能,沒有達到最大的優化策略。

因此,從JDK1.2開始,提供了四種類型的引用:強引用(StrongReference)、軟引用(SoftReference)、弱引用(WeakReference)和虛引用(PhantomReference)。主要有兩個目的:

可以在代碼中決定某些對象的生命周期;

優化JVM的垃圾回收機制。

關于GC

什么是 GC(GabageCollection)?
GC通常是運行在一個獨立的、優先級比較低的線程中,實時監測并釋放“無效”的內存。

什么是“無效"的內存單元?
一般GC采用引用計數法來判斷一個內存單元(一個變量)是否是無效的內存。
引用計數法(引用計數法只是GC中一種常用的方法,還會用到年代方法等)是指一個變量或一塊內存當前被引用的次數,如果引用次數為0,則表示這個變量或這塊內存未被引用,因此GC“有可能”去釋放它 ,為什么說有可能?首先GC運行在一個獨立的、優先級比較低的線程中,其次GC回收的具體工作也是比較復雜的,比如說需要釋放大量內存的時候,而CPU資源又相對緊張,GC可能會選擇性地釋放一些內存資源,具體回收方法取決于GC內部的算法。

四種引用類型 強引用

強引用是最普遍的引用,如果一個對象具有強引用,垃圾回收器不會回收該對象,當內存空間不足時,JVM 寧愿拋出 OutOfMemoryError異常;只有當這個對象沒有被引用時,才有可能會被回收。

package com.lzumetal.jvmtest;

import java.util.ArrayList;
import java.util.List;

public class StrongReferenceTest {

    static class BigObject {
        private Byte[] bytes = new Byte[1024 * 1024];
    }


    public static void main(String[] args) {
        List list = new ArrayList<>();
        while (true) {
            BigObject obj = new BigObject();
            list.add(obj);
        }
    }
}

BigObject obj = new BigObject()創建的這個對象時就是強引用,上面的main方法最終將拋出OOM異常:

Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
    at com.lzumetal.jvm.StrongReferenceTest$BigObject.(StrongReferenceTest.java:9)
    at com.lzumetal.jvm.StrongReferenceTest.main(StrongReferenceTest.java:16)
軟引用

如果一個對象只具有軟引用,則

當內存空間足夠,垃圾回收器就不會回收它。

當內存空間不足了,就會回收該對象。
JVM會優先回收長時間閑置不用的軟引用的對象,對那些剛剛構建的或剛剛使用過的“新”軟引用對象會盡可能保留。

如果回收完還沒有足夠的內存,才會拋出內存溢出異常。只要垃圾回收器沒有回收它,該對象就可以被程序使用。

軟引用是用來描述一些有用但并不是必需的對象,適合用來實現緩存(比如瀏覽器的‘后退’按鈕使用的緩存),內存空間充足的時候將數據緩存在內存中,如果空間不足了就將其回收掉。

軟引用在Java中用java.lang.ref.SoftReference類來表示。為了方便測試,在下面這個示例中我設置了JVM的內存為8M,在IDEA的Run——>EditConfigiratons中設置參數:-Xms8m -Xmx8m -XX:+PrintGCDetails

代碼:

package com.lzumetal.jvmtest;

import java.lang.ref.SoftReference;

public class SoftReferenceTest {

    static class Person {

        private String name;
        private Byte[] bytes = new Byte[1024 * 1024];

        public Person(String name) {
            this.name = name;
        }
    }


    public static void main(String[] args) throws InterruptedException {
        Person person = new Person("張三");
        SoftReference softReference = new SoftReference<>(person);
        
        person = null;  //去掉強引用,new Person("張三")的這個對象就只有軟引用了     

        System.gc();
        Thread.sleep(1000);

        System.err.println("軟引用的對象 ------->" + softReference.get());
    }
}

運行main方法,控制臺輸出:

[GC (Allocation Failure) [PSYoungGen: 1536K->504K(2048K)] 1536K->748K(7680K), 0.0118019 secs] [Times: user=0.08 sys=0.00, real=0.01 secs] 
[GC (System.gc()) [PSYoungGen: 1005K->496K(2048K)] 5346K->4868K(7680K), 0.0025626 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 
[Full GC (System.gc()) [PSYoungGen: 496K->0K(2048K)] [ParOldGen: 4372K->4773K(5632K)] 4868K->4773K(7680K), [Metaspace: 3466K->3466K(1056768K)], 0.0083134 secs] [Times: user=0.01 sys=0.00, real=0.01 secs] 
軟引用的對象 ------->com.lzumetal.jvmtest.SoftReferenceTest$Person@6d6f6e28
Heap
 PSYoungGen      total 2048K, used 45K [0x00000000ffd80000, 0x0000000100000000, 0x0000000100000000)
  eden space 1536K, 2% used [0x00000000ffd80000,0x00000000ffd8b7b8,0x00000000fff00000)
  from space 512K, 0% used [0x00000000fff80000,0x00000000fff80000,0x0000000100000000)
  to   space 512K, 0% used [0x00000000fff00000,0x00000000fff00000,0x00000000fff80000)
 ParOldGen       total 5632K, used 4773K [0x00000000ff800000, 0x00000000ffd80000, 0x00000000ffd80000)
  object space 5632K, 84% used [0x00000000ff800000,0x00000000ffca9498,0x00000000ffd80000)
 Metaspace       used 3474K, capacity 4500K, committed 4864K, reserved 1056768K
  class space    used 382K, capacity 388K, committed 512K, reserved 1048576K

雖然調用System.gc()后JVM并不一定會立刻進行GC操作,但從上面這段輸出可以看到JVM確實進行了GC,但是軟引用的對象并沒有被回收掉,說明現在內存空間還足夠,JVM暫時還不會回收軟引用的對象。

把main方法改成如下:

    public static void main(String[] args) throws InterruptedException {
        Person person = new Person("張三");
        SoftReference softReference = new SoftReference<>(person);

        person = null;//去掉強引用,new Person("張三")的這個對象就只有軟引用了

        Person anotherPerson = new Person("李四");
        Thread.sleep(1000);

        System.err.println("軟引用的對象 ------->" + softReference.get());
    }

因為這里JVM內存只有8M,沒有足夠的空間同時保留兩個Person對象(我已經測試過了:new兩個強引用的Person對象就會報OOM),所以當我再new Person("李四")時,也是會觸發JVM的GC的,同時因為前面的new Person("張三")只有軟引用了,它會被回收掉。

[GC (Allocation Failure) [PSYoungGen: 1536K->504K(2048K)] 1536K->664K(7680K), 0.0009884 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 
[GC (Allocation Failure) [PSYoungGen: 1006K->504K(2048K)] 5262K->4848K(7680K), 0.0077414 secs] [Times: user=0.06 sys=0.00, real=0.01 secs] 
[GC (Allocation Failure) [PSYoungGen: 504K->504K(2048K)] 4848K->4872K(7680K), 0.0017661 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 
[Full GC (Allocation Failure) [PSYoungGen: 504K->0K(2048K)] [ParOldGen: 4368K->4773K(5632K)] 4872K->4773K(7680K), [Metaspace: 3465K->3465K(1056768K)], 0.0201011 secs] [Times: user=0.08 sys=0.00, real=0.02 secs] 
[GC (Allocation Failure) [PSYoungGen: 0K->0K(2048K)] 4773K->4773K(7680K), 0.0039905 secs] [Times: user=0.06 sys=0.00, real=0.00 secs] 
[Full GC (Allocation Failure) [PSYoungGen: 0K->0K(2048K)] [ParOldGen: 4773K->659K(5632K)] 4773K->659K(7680K), [Metaspace: 3465K->3465K(1056768K)], 0.0103549 secs] [Times: user=0.00 sys=0.00, real=0.01 secs] 
軟引用的對象 ------->null
Heap
 PSYoungGen      total 2048K, used 45K [0x00000000ffd80000, 0x0000000100000000, 0x0000000100000000)
  eden space 1536K, 2% used [0x00000000ffd80000,0x00000000ffd8b7b8,0x00000000fff00000)
  from space 512K, 0% used [0x00000000fff80000,0x00000000fff80000,0x0000000100000000)
  to   space 512K, 0% used [0x00000000fff00000,0x00000000fff00000,0x00000000fff80000)
 ParOldGen       total 5632K, used 4755K [0x00000000ff800000, 0x00000000ffd80000, 0x00000000ffd80000)
  object space 5632K, 84% used [0x00000000ff800000,0x00000000ffca4c80,0x00000000ffd80000)
 Metaspace       used 3473K, capacity 4500K, committed 4864K, reserved 1056768K
  class space    used 382K, capacity 388K, committed 512K, reserved 1048576K
ReferenceQueue

SoftReference對象是用來保存軟引用,但它同時也是一個Java對象。所以,當軟可及對象被回收之后,雖然這個SoftReference對象的get()方法返回null,但SoftReference對象本身并不是null,而此時這個SoftReference對象已經不再具有存在的價值,需要一個適當的清除機制,避免大量SoftReference對象帶來的內存泄漏。

在java.lang.ref包里還提供了ReferenceQueue。如果在創建SoftReference對象的時候,使用了一個ReferenceQueue對象作為參數提供給SoftReference的構造方法,如:

    Person person = new Person("張三");
    ReferenceQueue queue = new ReferenceQueue<>();
    SoftReference softReference = new SoftReference(person, queue);

在SoftReference所軟引用的Person對象被垃圾回收時,JVM會先將softReference對象添加到ReferenceQueue這個隊列中。當我們調用ReferenceQueue的poll()方法,如果這個隊列中不是空隊列,那么將返回并移除前面添加的那個Reference對象。
還是上面的那個例子,測試代碼:

    public static void main(String[] args) throws InterruptedException {
        Person person = new Person("張三");
        ReferenceQueue queue = new ReferenceQueue<>();
        SoftReference softReference = new SoftReference(person, queue);

        person = null;//去掉強引用,new Person("張三")的這個對象就只有軟引用了

        Person anotherPerson = new Person("李四");
        Thread.sleep(1000);

        System.err.println("軟引用的對象 ------->" + softReference.get());

        Reference softPollRef = queue.poll();
        if (softPollRef != null) {
            System.err.println("SoftReference對象中保存的軟引用對象已經被GC,準備清理SoftReference對象");
            //清理softReference
        }
    }

控制臺輸出:

[GC (Allocation Failure) [PSYoungGen: 1536K->504K(2048K)] 1536K->728K(7680K), 0.0022378 secs] [Times: user=0.03 sys=0.05, real=0.00 secs] 
[GC (Allocation Failure) [PSYoungGen: 1036K->504K(2048K)] 5356K->4840K(7680K), 0.0027540 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 
[GC (Allocation Failure) [PSYoungGen: 504K->504K(2048K)] 4840K->4840K(7680K), 0.0048557 secs] [Times: user=0.00 sys=0.00, real=0.01 secs] 
[Full GC (Allocation Failure) [PSYoungGen: 504K->0K(2048K)] [ParOldGen: 4336K->4774K(5632K)] 4840K->4774K(7680K), [Metaspace: 3468K->3468K(1056768K)], 0.0087802 secs] [Times: user=0.11 sys=0.00, real=0.01 secs] 
[GC (Allocation Failure) [PSYoungGen: 0K->0K(2048K)] 4774K->4774K(7680K), 0.0005462 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 
[Full GC (Allocation Failure) [PSYoungGen: 0K->0K(2048K)] [ParOldGen: 4774K->659K(5632K)] 4774K->659K(7680K), [Metaspace: 3468K->3468K(1056768K)], 0.0104794 secs] [Times: user=0.05 sys=0.02, real=0.01 secs] 
軟引用的對象 ------->null
SoftReference對象中保存的軟引用對象已經被GC,準備清理SoftReference對象
Heap
 PSYoungGen      total 2048K, used 45K [0x00000000ffd80000, 0x0000000100000000, 0x0000000100000000)
  eden space 1536K, 2% used [0x00000000ffd80000,0x00000000ffd8b7b8,0x00000000fff00000)
  from space 512K, 0% used [0x00000000fff80000,0x00000000fff80000,0x0000000100000000)
  to   space 512K, 0% used [0x00000000fff00000,0x00000000fff00000,0x00000000fff80000)
 ParOldGen       total 5632K, used 4755K [0x00000000ff800000, 0x00000000ffd80000, 0x00000000ffd80000)
  object space 5632K, 84% used [0x00000000ff800000,0x00000000ffca4d70,0x00000000ffd80000)
 Metaspace       used 3476K, capacity 4500K, committed 4864K, reserved 1056768K
  class space    used 382K, capacity 388K, committed 512K, reserved 1048576K
弱引用

弱引用與軟引用的區別在于:只具有弱引用的對象擁有更短暫的生命周期,它只能生存到下一次垃圾收集發生之前。當垃圾回收器掃描到只具有弱引用的對象時,無論當前內存空間是否足夠,都會回收它。不過,由于垃圾回收器是一個優先級很低的線程,因此不一定會很快發現那些只具有弱引用的對象。

弱引用也可以和一個引用隊列(ReferenceQueue)聯合使用。

使用場景:一個對象只是偶爾使用,希望在使用時能隨時獲取,但也不想影響對該對象的垃圾收集,則可以考慮使用弱引用來指向該對象。

參考上面的代碼示例,測試弱引用:

    public static void main(String[] args) throws InterruptedException {
        Person person = new Person("張三");
        ReferenceQueue queue = new ReferenceQueue<>();
        WeakReference weakReference = new WeakReference(person, queue);

        person = null;//去掉強引用,new Person("張三")的這個對象就只有軟引用了

        System.gc();
        Thread.sleep(1000);
        System.err.println("弱引用的對象 ------->" + weakReference.get());

        Reference weakPollRef = queue.poll();   //poll()方法是有延遲的
        if (weakPollRef != null) {
            System.err.println("WeakReference對象中保存的弱引用對象已經被GC,下一步需要清理該Reference對象");
            //清理softReference
        } else {
            System.err.println("WeakReference對象中保存的軟引用對象還沒有被GC,或者被GC了但是獲得對列中的引用對象出現延遲");
        }
    }
虛引用

與其他三種引用都不同,虛引用并不會決定對象的生命周期。如果一個對象僅持有虛引用,那么它就和沒有任何引用一樣,在任何時候都可能被垃圾回收。

虛引用主要用來跟蹤對象被垃圾回收的活動。虛引用與軟引用和弱引用的一個區別在于:虛引用必須和引用隊列(ReferenceQueue)聯合使用。當垃 圾回收器準備回收一個對象時,如果發現它還有虛引用,就會在回收對象的內存之前,把這個虛引用加入到與之關聯的引用隊列中。

Object object = new Object();
ReferenceQueue queue = new ReferenceQueue ();
PhantomReference pr = new PhantomReference (object, queue); 

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

在實際程序設計中一般很少使用弱引用與虛引用,使用軟引用的情況較多,這是因為軟引用可以加速JVM對垃圾內存的回收速度,可以維護系統的運行安全,防止內存溢出(OutOfMemory)等問題的產生。

本文代碼已上傳至我的GitHub

文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。

轉載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/71198.html

相關文章

  • Java四種引用簡介

    摘要:簡單來說就是引用和引用隊列關聯起來引用的構造函數傳入隊列,然后引用被回收的時候會被添加到隊列中,然后使用方法可以返回引用。 引語: ????我們知道java相比C,C++中沒有令人頭痛的指針,但是卻有和指針作用相似的引用對象(Reference),就是常說的引用,比如,Object obj = new Object();這個obj就是引用,它指向的是真正的對象Object的地址,不過今...

    springDevBird 評論0 收藏0
  • Java中的四種引用引用引用引用、虛引用

    摘要:在之后,對引用的概念進行了擴充,將引用分為強引用軟引用弱引用虛引用種,這種引用強度依次逐漸減弱。軟引用是用來描述一些還有用但并非必需的對象。虛引用也稱為幽靈引用或者幻影引用,它是最弱的一種引用關系。 以下內容摘自《深入理解Java虛擬機 JVM高級特性與最佳實踐》第2版,強烈推薦沒有看過的同學閱讀,讀完的感覺就是原來學的都是些什么瘠薄東西(╯‵□′)╯︵┴─┴ 在JDK1.2以前,Ja...

    wwolf 評論0 收藏0
  • java中的四種引用

    摘要:如果想中斷強引用和某個對象之間的關聯,可以顯式地將引用賦值為,這樣一來的話,在合適的時間就會回收該對象。不過由于垃圾回收器是一個優先級較低的線程,所以并不一定能迅速發現弱引用對象。 強引用,軟引用,弱引用,虛引用。不同的引用類型主要體現在GC上: △強引用:如果一個對象具有強引用,它就不會被垃圾回收器回收。即使當前內存空間不足,JVM也不會回收它,而是拋出 OutOfMemoryErr...

    peixn 評論0 收藏0

發表評論

0條評論

makeFoxPlay

|高級講師

TA的文章

閱讀更多
最新活動
閱讀需要支付1元查看
<