Android中使用Handler造成內(nèi)存泄露的分析和解決方法

轉(zhuǎn)自rengwuxian

什么是內(nèi)存泄露蘸泻?
Java使用有向圖機制永品,通過GC自動檢查內(nèi)存中的對象(什么時候檢查由虛擬機決定)滚躯,如果GC發(fā)現(xiàn)一個或一組對象為不可到達狀態(tài)圃酵,則將該對象從內(nèi)存中回收柳畔。也就是說,一個對象不被任何引用所指向郭赐,則該對象會在被GC發(fā)現(xiàn)的時候被回收薪韩;另外确沸,如果一組對象中只包含互相的引用,而沒有來自它們外部的引用(例如有兩個對象A和B互相持有引用俘陷,但沒有任何外部對象持有指向A或B的引用)罗捎,這仍然屬于不可到達,同樣會被GC回收拉盾。

獲取Message實例推薦方法(不推薦使用new Message):
- Message.obtain()
- Handler.obtainMessage()

Android中使用Handler造成內(nèi)存泄露的原因

Handler mHandler = new Handler() {
    @Override
    public void handleMessage(Message msg) {
        mImageView.setImageBitmap(mBitmap);
    }
}

上面是一段簡單的Handler的使用桨菜。當(dāng)使用內(nèi)部類(包括匿名類)來創(chuàng)建Handler的時候,Handler對象會隱式地持有一個外部類對象(通常是一個Activity)的引用(不然你怎么可能通過Handler來操作Activity中的View捉偏?)倒得。

而Handler通常會伴隨著一個耗時的后臺線程(例如從網(wǎng)絡(luò)拉取圖片)一起出現(xiàn),這個后臺線程在任務(wù)執(zhí)行完畢(例如圖片下載完畢)之后夭禽,通過消息機制通知Handler霞掺,然后Handler把圖片更新到界面。

然而讹躯,如果用戶在網(wǎng)絡(luò)請求過程中關(guān)閉了Activity菩彬,正常情況下,Activity不再被使用潮梯,它就有可能在GC檢查時被回收掉挤巡,但由于這時線程尚未執(zhí)行完,而該線程持有Handler的引用(不然它怎么發(fā)消息給Handler酷麦?),這個Handler又持有Activity的引用喉恋,就導(dǎo)致該Activity無法被回收(即內(nèi)存泄露)沃饶,直到網(wǎng)絡(luò)請求結(jié)束(例如圖片下載完畢)。

另外轻黑,如果你執(zhí)行了Handler的postDelayed()方法糊肤,該方法會將你的Handler裝入一個Message,并把這條Message推到MessageQueue中氓鄙,那么在你設(shè)定的delay到達之前馆揉,會有一條MessageQueue -> Message -> Handler -> Activity的鏈,導(dǎo)致你的Activity被持有引用而無法被回收抖拦。

內(nèi)存泄漏的危害
只有一個升酣,那就是虛擬機占用內(nèi)存過高,導(dǎo)致OOM(內(nèi)存溢出)态罪,程序出錯噩茄。對于Android應(yīng)用來說,就是你的用戶打開一個Activity复颈,使用完之后關(guān)閉它绩聘,內(nèi)存泄露;又打開,又關(guān)閉凿菩,又泄露机杜;幾次之后,程序占用內(nèi)存超過系統(tǒng)限制衅谷,F(xiàn)C椒拗。

使用Handler導(dǎo)致內(nèi)存泄露的解決方法

方法一:通過程序邏輯來進行保護。

  1. 在關(guān)閉Activity的時候停掉你的后臺線程会喝。線程停掉了陡叠,就相當(dāng)于切斷了Handler和外部連接的線,Activity自然會在合適的時候被回收肢执。
  2. 如果你的Handler是被delay的Message持有了引用枉阵,那么使用相應(yīng)的Handler的removeCallbacks()方法,把消息對象從消息隊列移除就行了预茄。

方法二:將Handler聲明為靜態(tài)類兴溜。
靜態(tài)類不持有外部類的對象,所以你的Activity可以隨意被回收耻陕。代碼如下:

static class MyHandler extends Handler {
    @Override
    public void handleMessage(Message msg) {
        mImageView.setImageBitmap(mBitmap);
    }
}

但其實沒這么簡單拙徽。使用了以上代碼之后,你會發(fā)現(xiàn)诗宣,由于Handler不再持有外部類對象的引用膘怕,導(dǎo)致程序不允許你在Handler中操作Activity中的對象了。所以你需要在Handler中增加一個對Activity的弱引用(WeakReference):

    /*
    * handler不一定需要static,只是一般全局需要一個hanlder就可以召庞,
    * 所以習(xí)慣性的會寫成static的岛心,這樣在別的activity里面也可以使用這個hanlder
    */
    static class ScanImgHandler extends Handler {
        WeakReference<MainActivity> mWeakReference;

        public ScanImgHandler(MainActivity activity) {
            mWeakReference = new WeakReference<MainActivity>(activity);
        }

        @Override
        public void handleMessage(Message msg) {
            final MainActivity activity = mWeakReference.get();
            if (activity != null) {
                switch (msg.what) {
                    case SCAN_OK:
                        activity.mProgressDialog.cancel();
                        break;
                }
            }
        }
    }

什么是WeakReference?
WeakReference弱引用篮灼,與強引用(即我們常說的引用)相對忘古,它的特點是,GC在回收時會忽略掉弱引用诅诱,即就算有弱引用指向某對象髓堪,但只要該對象沒有被強引用指向(實際上多數(shù)時候還要求沒有軟引用,但此處軟引用的概念可以忽略)娘荡,該對象就會在被GC檢查到時回收掉干旁。對于上面的代碼,用戶在關(guān)閉Activity之后炮沐,就算后臺線程還沒結(jié)束疤孕,但由于僅有一條來自Handler的弱引用指向Activity,所以GC仍然會在檢查的時候把Activity回收掉央拖。這樣祭阀,內(nèi)存泄露的問題就不會出現(xiàn)了鹉戚。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市专控,隨后出現(xiàn)的幾起案子抹凳,更是在濱河造成了極大的恐慌,老刑警劉巖伦腐,帶你破解...
    沈念sama閱讀 222,183評論 6 516
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件赢底,死亡現(xiàn)場離奇詭異,居然都是意外死亡柏蘑,警方通過查閱死者的電腦和手機幸冻,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,850評論 3 399
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來咳焚,“玉大人洽损,你說我怎么就攤上這事「锇耄” “怎么了碑定?”我有些...
    開封第一講書人閱讀 168,766評論 0 361
  • 文/不壞的土叔 我叫張陵,是天一觀的道長又官。 經(jīng)常有香客問我延刘,道長,這世上最難降的妖魔是什么六敬? 我笑而不...
    開封第一講書人閱讀 59,854評論 1 299
  • 正文 為了忘掉前任碘赖,我火速辦了婚禮,結(jié)果婚禮上外构,老公的妹妹穿的比我還像新娘普泡。我一直安慰自己,他們只是感情好典勇,可當(dāng)我...
    茶點故事閱讀 68,871評論 6 398
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著叮趴,像睡著了一般割笙。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上眯亦,一...
    開封第一講書人閱讀 52,457評論 1 311
  • 那天伤溉,我揣著相機與錄音,去河邊找鬼妻率。 笑死乱顾,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的宫静。 我是一名探鬼主播走净,決...
    沈念sama閱讀 40,999評論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼券时,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了伏伯?” 一聲冷哼從身側(cè)響起橘洞,我...
    開封第一講書人閱讀 39,914評論 0 277
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎说搅,沒想到半個月后炸枣,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,465評論 1 319
  • 正文 獨居荒郊野嶺守林人離奇死亡弄唧,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,543評論 3 342
  • 正文 我和宋清朗相戀三年适肠,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片候引。...
    茶點故事閱讀 40,675評論 1 353
  • 序言:一個原本活蹦亂跳的男人離奇死亡侯养,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出背伴,到底是詐尸還是另有隱情沸毁,我是刑警寧澤,帶...
    沈念sama閱讀 36,354評論 5 351
  • 正文 年R本政府宣布傻寂,位于F島的核電站息尺,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏疾掰。R本人自食惡果不足惜搂誉,卻給世界環(huán)境...
    茶點故事閱讀 42,029評論 3 335
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望静檬。 院中可真熱鬧炭懊,春花似錦、人聲如沸拂檩。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,514評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽稻励。三九已至父阻,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間望抽,已是汗流浹背加矛。 一陣腳步聲響...
    開封第一講書人閱讀 33,616評論 1 274
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留煤篙,地道東北人斟览。 一個月前我還...
    沈念sama閱讀 49,091評論 3 378
  • 正文 我出身青樓,卻偏偏與公主長得像辑奈,于是被迫代替她去往敵國和親苛茂。 傳聞我的和親對象是個殘疾皇子已烤,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,685評論 2 360

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