java 多種引用的使用說明

前言

總所周知, java不同于c/c++臭墨,它不需要程序員自已來管理內(nèi)存(分配赔嚎,釋放內(nèi)存),java 會自己來管理內(nèi)存,比如銷毀某些不再被使用的對象尤误。這些操作都是在一個后臺線程默默進行(Garbage Collector Thread)侠畔,也就是垃圾收集器線程,根據(jù)jvm實現(xiàn)的策略來釋放對象內(nèi)存损晤。但是程序編寫者卻無法控制這個后臺線程软棺,無法讓它在你想要的時候開始釋放內(nèi)存,銷毀對象尤勋,按照你的規(guī)定來銷毀那些對象喘落,釋放內(nèi)存,這些都是都jvm自己控制的最冰。但是隨著 java.lang.ref這個包下的類的引進瘦棋,程序員擁有了一點點控制你創(chuàng)建的對象何時釋放,銷毀的權(quán)利暖哨,當(dāng)然只是一點點赌朋。那接下來就來看看這些類和java中的四種引用類型有何對應(yīng)關(guān)系。先來看看這四種引用類型篇裁,因為jvm在進行垃圾收集的時候沛慢,需要判斷哪些對象需要銷毀,這時就與這幾種引用類型相關(guān)茴恰。

以下是這幾種引用類型:

  1. 強引用(Strong References)
    強引用類型是我們平時寫代碼的時候最常用的引用颠焦,而大部分人往往都會忽略這個概念斩熊,都成一種理所當(dāng)然的事情了往枣。
    接下來看看下面這個簡單的例子:
public class Main {


    public static void main(String[] args) {

        //創(chuàng)建一個對象,new出來的對象都是分配在java堆中的
        Sample sample = new Sample();   //sample這個引用就是強引用

        sample = null;                  //將這個引用指向空指針,
                                        //那么上面那個剛new來的對象就沒用任何其它有效的引用指向它了
                                        //也就說該對象對于垃圾收集器是符合條件的
                                        //因此在接下來某個時間點 GC進行收集動作的時候, 該對象將會被銷毀粉渠,內(nèi)存被釋放

    }

}

class Sample {

}

也可以畫個簡單的圖理解一下:


20170604105301187.png
  1. 軟引用(Soft References)
    軟引用在java.lang.ref包中有與之對應(yīng)的類java.lang.ref.SoftReference分冈。
    重點: 被弱引用指向的對象不會被垃圾收集器收集(即使該對象沒有強引用指向它),除非jvm使用內(nèi)存不夠了霸株,才會對這類對象進行銷毀雕沉,釋放內(nèi)存。舉個簡單的例子:
public class Main {

    public static void main(String[] args) {

        //創(chuàng)建一個對象去件,new出來的對象都是分配在java堆中的
        Sample sample = new Sample();   //sample這個引用就是強引用

        //創(chuàng)建一個軟引用指向這個對象   那么此時就有兩個引用指向Sample對象
        SoftReference<Sample> softRef = new SoftReference<Sample>(sample);

        //將強引用指向空指針 那么此時只有一個軟引用指向Sample對象
        //注意:softRef這個引用也是強引用坡椒,它是指向SoftReference這個對象的
        //那么這個軟引用在哪呢? 可以跟一下java.lang.Reference的源碼 
        //private T referent; 這個才是軟引用尤溜, 只被jvm使用
        sample = null;

        //可以重新獲得Sample對象倔叼,并用一個強引用指向它
        sample = softRef.get();
    }

}

class Sample {

}

有興趣可以去看看Reference的源碼。


20170604112225748.png

現(xiàn)在是不是想到了軟引用的一個使用場景宫莱,它相比與強引用可以避免OOM丈攒。

現(xiàn)在可以簡單的測試下 當(dāng)jvm內(nèi)存不足的情況下,軟引用的回收情況。
為了更快的看到結(jié)果巡验,我限制了jvm的最大堆內(nèi)存 -Xmx100m 為100m

public class Main {

    private static final List<Object> TEST_DATA = new LinkedList<>();


    public static void main(String[] args) throws InterruptedException {

        //創(chuàng)建一個對象际插,new出來的對象都是分配在java堆中的
        Sample sample = new Sample();   //sample這個引用就是強引用

        //創(chuàng)建一個軟引用指向這個對象   那么此時就有兩個引用指向Sample對象
        SoftReference<Sample> softRef = new SoftReference<Sample>(sample);

        //將強引用指向空指針 那么此時只有一個軟引用指向Sample對象
        //注意:softRef這個引用也是強引用,它是指向SoftReference這個對象的
        //那么這個軟引用在哪呢显设? 可以跟一下java.lang.Reference的源碼
        //private T referent; 這個才是軟引用框弛, 只被jvm使用
        sample = null;

        //可以重新獲得Sample對象,并用一個強引用指向它
        //sample = softRef.get();

        new Thread(){
            @Override
            public void run() {
                while (true) {
                    System.out.println(softRef.get());
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    TEST_DATA.add(new byte[1024 * 1024 * 5]);
                }
            }
        }.start();

        Thread.currentThread().join();
    }

}

class Sample {
    private final byte[] data;

    public Sample() {
        data = new byte[1024 * 1024 * 10];
    }
}

可以看到當(dāng)jvm內(nèi)存耗盡的時候捕捂,會將弱引用的對象進行回收 上面的例子的10m功咒,且剛好還可以分配兩次 5m一次 ,輸出了兩次null也證明了這一點

當(dāng)然我們在創(chuàng)建軟引用時绞蹦,還可以傳入ReferenceQueue力奋,這個隊列有啥用呢? 當(dāng)jvm回收某個軟引用對象之后會將該SoftReference對象(例子中的softRef對象)添加進這個隊列幽七,因此我們就知道這個對象啥時候被回收了景殷,可以做一些我們想做的操作。

  1. 弱引用(Weak References)
    弱引用會被jvm忽略澡屡,也就說在GC進行垃圾收集的時候猿挚,如果一個對象只有弱引用指向它,那么和沒有引用指向它是一樣的效果驶鹉,jvm都會對它就行果斷的銷毀绩蜻,釋放內(nèi)存。其實這個特性是很有用的室埋,jdk也提供了java.util.WeakHashMap這么一個key為弱引用的Map办绝。比如某個資源對象你要釋放(比如 db connection), 但是如果被其它map作為key強引用了,就無法釋放姚淆,被jvm收集孕蝉。

來個簡單的例子:

public class Main {

    private static final List<Object> TEST_DATA = new LinkedList<>();

    private static final ReferenceQueue<Sample> QUEUE = new ReferenceQueue<>();


    public static void main(String[] args) {

        //創(chuàng)建一個對象,new出來的對象都是分配在java堆中的
        Sample sample = new Sample();   //sample這個引用就是強引用

        //創(chuàng)建一個弱引用指向這個對象   那么此時就有兩個引用指向Sample對象
        //SoftReference<Sample> softRef = new SoftReference<Sample>(sample, QUEUE);
        WeakReference<Sample> weakRef = new WeakReference<Sample>(sample, QUEUE);
        //將強引用指向空指針 那么此時只有一個弱引用指向Sample對象
        //注意:softRef這個引用也是強引用腌逢,它是指向SoftReference這個對象的
        //那么這個弱引用在哪呢降淮? 可以跟一下java.lang.Reference的源碼
        //private T referent; 這個才是弱引用, 只被jvm使用
        sample = null;

        //可以重新獲得Sample對象搏讶,并用一個強引用指向它
        //sample = softRef.get();

        new Thread(){
            @Override
            public void run() {
                while (true) {
                    System.out.println(weakRef.get());
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                        Thread.currentThread().interrupt();
                    }
                    TEST_DATA.add(new byte[1024 * 1024 * 5]);
                }
            }
        }.start();

        new Thread(){
            @Override
            public void run() {
                while (true) {
                    Reference<? extends Sample> poll = QUEUE.poll();
                    if (poll != null) {
                        System.out.println("--- 弱引用對象被jvm回收了 ---- " + poll);
                        System.out.println("--- 回收對象 ---- " + poll.get());
                    }
                }
            }
        }.start();

        try {
            Thread.currentThread().join();
        } catch (InterruptedException e) {
            System.exit(1);
        }
    }

}

class Sample {
    private final byte[] data;

    public Sample() {
        data = new byte[1024 * 1024 * 10];
    }
}
  1. 虛幻引用(Phantom References)
    虛幻應(yīng)用和弱引用的回收機制差不多佳鳖,都是可以被隨時回收的。但是不同的地方是媒惕,它的構(gòu)造方法必須強制傳入ReferenceQueue系吩,因為在jvm回收前(重點: 對,就是回收前吓笙,軟引用和弱引用都是回收后)淑玫,會將PhantomReference對象加入ReferenceQueue中; 還有一點就是PhantomReference.get()方法永遠返回空,不管對象有沒有被回收。

參考:https://blog.csdn.net/rodbate/article/details/72857447

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末絮蒿,一起剝皮案震驚了整個濱河市尊搬,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌土涝,老刑警劉巖佛寿,帶你破解...
    沈念sama閱讀 217,185評論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異但壮,居然都是意外死亡冀泻,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,652評論 3 393
  • 文/潘曉璐 我一進店門蜡饵,熙熙樓的掌柜王于貴愁眉苦臉地迎上來弹渔,“玉大人,你說我怎么就攤上這事溯祸≈ǎ” “怎么了?”我有些...
    開封第一講書人閱讀 163,524評論 0 353
  • 文/不壞的土叔 我叫張陵焦辅,是天一觀的道長博杖。 經(jīng)常有香客問我,道長筷登,這世上最難降的妖魔是什么剃根? 我笑而不...
    開封第一講書人閱讀 58,339評論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮前方,結(jié)果婚禮上狈醉,老公的妹妹穿的比我還像新娘。我一直安慰自己镣丑,他們只是感情好舔糖,可當(dāng)我...
    茶點故事閱讀 67,387評論 6 391
  • 文/花漫 我一把揭開白布娱两。 她就那樣靜靜地躺著莺匠,像睡著了一般。 火紅的嫁衣襯著肌膚如雪十兢。 梳的紋絲不亂的頭發(fā)上趣竣,一...
    開封第一講書人閱讀 51,287評論 1 301
  • 那天,我揣著相機與錄音旱物,去河邊找鬼遥缕。 笑死,一個胖子當(dāng)著我的面吹牛宵呛,可吹牛的內(nèi)容都是我干的单匣。 我是一名探鬼主播,決...
    沈念sama閱讀 40,130評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼户秤!你這毒婦竟也來了码秉?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 38,985評論 0 275
  • 序言:老撾萬榮一對情侶失蹤鸡号,失蹤者是張志新(化名)和其女友劉穎转砖,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體鲸伴,經(jīng)...
    沈念sama閱讀 45,420評論 1 313
  • 正文 獨居荒郊野嶺守林人離奇死亡府蔗,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,617評論 3 334
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了汞窗。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片姓赤。...
    茶點故事閱讀 39,779評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖仲吏,靈堂內(nèi)的尸體忽然破棺而出模捂,到底是詐尸還是另有隱情,我是刑警寧澤蜘矢,帶...
    沈念sama閱讀 35,477評論 5 345
  • 正文 年R本政府宣布狂男,位于F島的核電站,受9級特大地震影響品腹,放射性物質(zhì)發(fā)生泄漏岖食。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,088評論 3 328
  • 文/蒙蒙 一舞吭、第九天 我趴在偏房一處隱蔽的房頂上張望泡垃。 院中可真熱鬧,春花似錦羡鸥、人聲如沸蔑穴。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,716評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽存和。三九已至,卻和暖如春衷旅,著一層夾襖步出監(jiān)牢的瞬間捐腿,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,857評論 1 269
  • 我被黑心中介騙來泰國打工柿顶, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留茄袖,地道東北人。 一個月前我還...
    沈念sama閱讀 47,876評論 2 370
  • 正文 我出身青樓嘁锯,卻偏偏與公主長得像宪祥,于是被迫代替她去往敵國和親聂薪。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,700評論 2 354

推薦閱讀更多精彩內(nèi)容