Java/Android中的強(qiáng)引用莺掠、軟引用衫嵌、弱引用、虛引用

轉(zhuǎn)自:
Java/Android中的強(qiáng)引用彻秆、軟引用楔绞、弱引用结闸、虛引用


引用分為四個(gè),從高到低的級(jí)別以此為強(qiáng)引用-軟引用-弱引用-虛引用.

  • 引用類型
類別 回收機(jī)制 用途 生存時(shí)間
強(qiáng)引用 從不回收 對(duì)象狀態(tài) JVM停止運(yùn)行時(shí)
軟引用SoftReference 內(nèi)存不足時(shí)進(jìn)行回收 緩存 內(nèi)存不足
弱引用WeakReference 對(duì)象不被引用時(shí)回收 緩存 GC運(yùn)行后
虛引用 對(duì)象被回收時(shí) 管理控制精確內(nèi)存穩(wěn)定性 unknown

1.強(qiáng)引用:

Qiang qiang = new Qiang();
Niu niu = new  Niu(qiang);

強(qiáng)引用例子,niu持有qiang的引用,當(dāng)qiang=null的時(shí)候,此時(shí)GC 應(yīng)該去回收Qiang,但是由于之前的實(shí)例,被niu持有,因此,并不能回收,導(dǎo)致內(nèi)存泄漏,典型的引用泄漏.

2.軟引用SoftReference

    A a = new A();
    SoftReference<A> aSoftRef = new SoftReference<>(a);
    A a1 = aSoftRef.get();

一個(gè)對(duì)象只具有軟引用,則內(nèi)存空間足夠酒朵,垃圾回收器就不會(huì)回收它桦锄;如果內(nèi)存空間不足了,就會(huì)回收這些對(duì)象的內(nèi)存蔫耽。
只要垃圾回收器沒有回收它结耀,該對(duì)象就可以被程序使用。

軟引用可以和一個(gè)引用隊(duì)列(ReferenceQueue)聯(lián)合使用匙铡,如果軟引用所引用的對(duì)象被垃圾回收图甜,Java虛擬機(jī)就會(huì)把這個(gè)軟引用加入到與之關(guān)聯(lián)的引用隊(duì)列中。

    A a = new A();
    ReferenceQueue refQueue = new ReferenceQueue();
    SoftReference<A> aSoftRef = new SoftReference<>(a, refQueue);
    A a1 = aSoftRef.get();

3.Android中的示例:

  • 案例1:
    在平常的Android開發(fā)者,有很多的圖片要顯示,如果是網(wǎng)絡(luò)圖片,則需要通過網(wǎng)絡(luò)解析獲取,但是,每次都從網(wǎng)絡(luò)解析圖片,會(huì)影響體驗(yàn),于是我們將會(huì)將請(qǐng)求到的圖片保存到本地.
    但是,這就產(chǎn)生了另一個(gè)問題:每次我們從本地獲取,相對(duì)與我們從網(wǎng)絡(luò)請(qǐng)求后,直接從內(nèi)存獲取,效率更低.于是我們就還要在內(nèi)存也緩存一份(層級(jí)著名的LRUCache 就是這3級(jí)緩存)
    但是因?yàn)閳D片的數(shù)量多,消耗內(nèi)存過大,內(nèi)存緩存的過程需要大量的內(nèi)存,內(nèi)存不夠就會(huì)OOM,這時(shí),便可以采用軟引用的技術(shù)解決問題

    private Map<String, SoftReference> softReferenceMap = new HashMap<>();

    /**
     * 
     * @param path
     */
    public void addBitmap(String path) {
        //強(qiáng)引用的bitmap對(duì)象
        //或者從網(wǎng)絡(luò)請(qǐng)求圖片Bitmap
        Bitmap bitmap = BitmapFactory.decodeFile(path);
        //軟引用的Bitmap對(duì)象
        SoftReference<Bitmap> softBitmap = new SoftReference<>(bitmap);
        //添加軟引用的Bitmap到map中時(shí)期緩存
        softReferenceMap.put(path, softBitmap);
    }


    public Bitmap getBitmap(String path) {
        //從緩存中取軟引用的bitmap對(duì)象
        SoftReference<Bitmap> softBitmap = softReferenceMap.get(path);
        //判斷 軟引用的 對(duì)象 是否已經(jīng)被回收
        if (null == softBitmap) {
            return null;
            //TODO: 進(jìn)行從SD卡讀取的操作
        }
        //取出Bitmap對(duì)象,如果內(nèi)存不足,軟引用對(duì)象被回收了,將取到 null
        Bitmap bitmap = softBitmap.get();
        return bitmap;
    }

在softBitmap.get()中獲取Bitmap的實(shí)例的強(qiáng)引用,在內(nèi)存充足的情況下不會(huì)回收軟引用對(duì)象,可以取出bitmap

內(nèi)存不足時(shí),softBitmap.get()不在返回bitamp直接返回null,軟引用被回收了

因此在獲取Bitmap的對(duì)象之前要判斷softBitmap == null是否為空,否則將會(huì)出現(xiàn)空指針異常.
這里,還可以擴(kuò)展從SD卡讀取緩存的操作

  • 案例2:
    設(shè)計(jì)給出了一張1080的全屏圖片,這張圖片假設(shè)500K,可以想象它的內(nèi)存消耗,通用使用軟引用來解決
    private void test() {
        ImageView imageView = findViewById(R.id.test_iv);
        BitmapFactory.Options options = new BitmapFactory.Options();
        options.inPreferredConfig = Bitmap.Config.ARGB_4444;
        //5.0后失效 設(shè)置了也沒有
        options.inPurgeable=true;
        options.outWidth=720;
        options.outHeight = 1280;
        Bitmap bitmap = BitmapFactory.decodeResource(getResources(),
                R.mipmap.avatar,
                options);
        Drawable drawable = new BitmapDrawable(getResources(), bitmap);
        SoftReference<Drawable> drawableSoftReference = new SoftReference<Drawable>(drawable);
            //判斷 是否 null 如果內(nèi)存不足,軟引用 被回收,那么就不展示在ImageView上
        if (drawableSoftReference != null) {
            imageView.setBackground(drawableSoftReference.get());
        }
    }

因此在特定的場景想要避免OOM的發(fā)生就盡量使用軟引用吧.

但是在Android中最好選擇Least Recently Used(LRU),在它內(nèi)部維護(hù)一個(gè)特定大小內(nèi)存,在內(nèi)存不足時(shí)會(huì)根據(jù)一系列的策略算法來進(jìn)行處理移除掉當(dāng)前一些緩存以便獲取新的內(nèi)空間用來緩存數(shù)據(jù).

4.弱引用WeakReference

 WeakReference<MainActivity> weakReference = new WeakReference<MainActivity>(new MainActivity()) ;

如果一個(gè)對(duì)象只具有弱引用,那么在垃圾回收線程掃描的過程中,一旦發(fā)現(xiàn)了,只有弱引用的對(duì)象,不管當(dāng)前內(nèi)存空間是否足夠,都會(huì)回收他的內(nèi)存.
不過,由于垃圾回收器是一個(gè)優(yōu)先級(jí)很低的線程,因此不一定會(huì)很快發(fā)現(xiàn)哪些只具有弱引用的對(duì)象.
弱引用可以喝一個(gè)引用對(duì)列(ReferenceQueue)配合使用,如果弱引用所引用的對(duì)象被垃圾回收,java虛擬機(jī)就會(huì)把這個(gè)弱引用加入到與之關(guān)聯(lián)的引用對(duì)列之中.

5.Android中的示例

比如一個(gè)Activity持有一個(gè)Handler,handler是匿名內(nèi)部類的形式,而非,靜態(tài)內(nèi)部類,那么handler就會(huì)持有此activity的引用,Handler作為一個(gè)耗時(shí)的異步線程的通信工具,如果在異步線程處理任務(wù)過程中,Activity關(guān)閉了,此時(shí)Activity應(yīng)該被回收,但是因?yàn)镠andler還持有Activity的引用,而了另一個(gè)"異步線程"持有handler的引用,那么,就將導(dǎo)致內(nèi)存泄漏

  • 解決方案:
      • 在Activity關(guān)閉的地方,停止線程,并把handler的消息隊(duì)列的所有消息對(duì)象移除
      • Handler改為靜態(tài)類
public class TestActivity extends AppCompatActivity {

    private MyHandler mHandler = new MyHandler(this);

    private static class MyHandler extends Handler {
        private WeakReference<Context> ctxRef;

        public MyHandler(Context context) {
            ctxRef = new WeakReference<>(context);

        }

        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            if (ctxRef.get() instanceof TestActivity) {
                ((TestActivity) ctxRef.get()).textView.setText("");
            }
        }
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        mHandler.removeCallbacksAndMessages(null);
    }

}

6.虛引用:

在對(duì)象銷毀時(shí)會(huì)被回收.

在Java中GC的運(yùn)行時(shí)間是不確定的,在Java里有一個(gè)finalize方法,在垃圾回收器準(zhǔn)備釋放內(nèi)存的時(shí)候鳖眼,會(huì)先調(diào)用finalize().但因?yàn)閮?nèi)存還沒有好耗盡,擬機(jī)不能保證在適當(dāng)?shù)臅r(shí)機(jī)調(diào)用finalize,因此垃圾回收期與finalize是不可靠的方法.

這時(shí)可以采用虛引用.比如一個(gè)固定的內(nèi)存,在明確知道一個(gè)bitmap回收之后會(huì)釋放一部分內(nèi)存,新釋放開辟的內(nèi)存就可以讓其他bitmap來使用,以此循環(huán)來達(dá)到內(nèi)存的穩(wěn)定性控制.

7.總結(jié)

在Android中比較常用便是 弱引用和軟引用了黑毅。

對(duì)于一些OOM等常規(guī)處理使用軟引用便可很好的解決,可以實(shí)現(xiàn)高速緩存.

對(duì)于偶爾使用的對(duì)象,并且隨時(shí)獲取到便使用弱引用來標(biāo)記

軟引用與弱引用的區(qū)別:只含有弱引用的對(duì)象的生命周期更短。在垃圾回收器線程掃描它所管轄的內(nèi)存區(qū)域的過程中钦讳,一旦發(fā)現(xiàn)了只具有弱引用的對(duì)象矿瘦,不管當(dāng)前內(nèi)存空間足夠與否,都會(huì)回收它的內(nèi)存愿卒。不過缚去,由于垃圾回收器是一個(gè)優(yōu)先級(jí)很低的線程,因此不一定會(huì)很快發(fā)現(xiàn)那些只具有弱引用的對(duì)象掘猿。

虛引用只要用于內(nèi)存的精準(zhǔn)控制,如Android中的ViewPager圖片的查看等等

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市唇跨,隨后出現(xiàn)的幾起案子稠通,更是在濱河造成了極大的恐慌,老刑警劉巖买猖,帶你破解...
    沈念sama閱讀 217,277評(píng)論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件改橘,死亡現(xiàn)場離奇詭異,居然都是意外死亡玉控,警方通過查閱死者的電腦和手機(jī)飞主,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,689評(píng)論 3 393
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來高诺,“玉大人碌识,你說我怎么就攤上這事∈” “怎么了筏餐?”我有些...
    開封第一講書人閱讀 163,624評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長牡拇。 經(jīng)常有香客問我魁瞪,道長穆律,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,356評(píng)論 1 293
  • 正文 為了忘掉前任导俘,我火速辦了婚禮峦耘,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘旅薄。我一直安慰自己辅髓,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,402評(píng)論 6 392
  • 文/花漫 我一把揭開白布赋秀。 她就那樣靜靜地躺著利朵,像睡著了一般。 火紅的嫁衣襯著肌膚如雪猎莲。 梳的紋絲不亂的頭發(fā)上绍弟,一...
    開封第一講書人閱讀 51,292評(píng)論 1 301
  • 那天,我揣著相機(jī)與錄音著洼,去河邊找鬼樟遣。 笑死,一個(gè)胖子當(dāng)著我的面吹牛身笤,可吹牛的內(nèi)容都是我干的豹悬。 我是一名探鬼主播,決...
    沈念sama閱讀 40,135評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼液荸,長吁一口氣:“原來是場噩夢(mèng)啊……” “哼瞻佛!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起娇钱,我...
    開封第一講書人閱讀 38,992評(píng)論 0 275
  • 序言:老撾萬榮一對(duì)情侶失蹤伤柄,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后文搂,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體适刀,經(jīng)...
    沈念sama閱讀 45,429評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,636評(píng)論 3 334
  • 正文 我和宋清朗相戀三年煤蹭,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了笔喉。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,785評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡硝皂,死狀恐怖常挚,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情稽物,我是刑警寧澤待侵,帶...
    沈念sama閱讀 35,492評(píng)論 5 345
  • 正文 年R本政府宣布,位于F島的核電站姨裸,受9級(jí)特大地震影響秧倾,放射性物質(zhì)發(fā)生泄漏怨酝。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,092評(píng)論 3 328
  • 文/蒙蒙 一那先、第九天 我趴在偏房一處隱蔽的房頂上張望农猬。 院中可真熱鬧,春花似錦售淡、人聲如沸斤葱。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,723評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽揍堕。三九已至,卻和暖如春汤纸,著一層夾襖步出監(jiān)牢的瞬間衩茸,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,858評(píng)論 1 269
  • 我被黑心中介騙來泰國打工贮泞, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留楞慈,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 47,891評(píng)論 2 370
  • 正文 我出身青樓啃擦,卻偏偏與公主長得像囊蓝,于是被迫代替她去往敵國和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子令蛉,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,713評(píng)論 2 354

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