Android內(nèi)存泄漏

概念

  • 內(nèi)存泄露 memory leak,是指程序在申請(qǐng)內(nèi)存后骡和,無(wú)法釋放已申請(qǐng)的內(nèi)存空間箍鼓。
    對(duì)象被更長(zhǎng)生命周期的對(duì)象持有引用崭参,導(dǎo)致無(wú)法被GC回收】羁В【無(wú)用對(duì)象無(wú)法被回收】
  • 內(nèi)存溢出 out of memory阵翎,是指程序在申請(qǐng)內(nèi)存時(shí)逢并,沒(méi)有足夠的內(nèi)存空間供其使用

影響

  • 無(wú)用對(duì)象無(wú)法及時(shí)釋放,占用內(nèi)存
  • 嚴(yán)重時(shí)造成內(nèi)存溢出

常見(jiàn)情況分析

Android多發(fā)生于Activity郭卫、Fragment等對(duì)象在生命周期結(jié)束后不能及時(shí)釋放

1. 單例模式

常見(jiàn)于單例模式的工具類需要持有Context對(duì)象砍聊,此情況下如果直接傳Activity對(duì)象來(lái)進(jìn)行初始化,會(huì)造成單例一直持有此Activity引用贰军,無(wú)法釋放玻蝌。

public class Singleton {

    private static Singleton sInstance;
    private Context mContext;

    private Singleton (Context context){
        this.mContext = context;
    }

    public static Singleton newInstance(Context context){
        if(sInstance == null){
            sInstance = new Singleton (context);
        }
        return sInstance;
    }
}

解決方案:

  • 如果單例模式必須持有context對(duì)象,需要使用與應(yīng)用生命周期一樣的Application對(duì)象
  • 對(duì)于工具類必須使用到activity等短生命周期對(duì)象的情況词疼,可以選擇僅在操作方法中作為參數(shù)傳入俯树,這樣在方法執(zhí)行完成后會(huì)可以正常釋放
public class Singleton {
private static Singleton sInstance;
 ......
  public void func(Activity activity){
      //do something
  }
}

2. 非靜態(tài)內(nèi)部類

由于非靜態(tài)內(nèi)部類、匿名內(nèi)部類等會(huì)持有外部類的引用贰盗,尤其需要注意使用Thread许饿、Runnable、AsyncTask等新開(kāi)線程的類時(shí)舵盈,常常習(xí)慣于直接使用匿名內(nèi)部類陋率,很容易造成外部類內(nèi)存泄漏。

class A{
  private mB = new B();
  //內(nèi)部類B持有外部類A的引用
  class B{
  //....
  }
}

解決方案:
使用靜態(tài)內(nèi)部類或者外部類


3. Handler

Handler 造成內(nèi)存泄漏的原因也是持有內(nèi)部類持有外部類的引用秽晚。

public class TestActivity extends Activity {
  int mCount =0;

  private Handler mHandler = new Handler(){
        @Override
        public void handleMessage(Message msg) {
          //收到消息計(jì)數(shù)+1
            super.handleMessage(msg);
            mCount++;
        }
    };
  //使用Handler 發(fā)送消息
  public void send(){
        Message message = Message.obtain();
        mHandler.sendMessageDelayed(message, 1000);
  }
}

mHandler是匿名內(nèi)部類而持有外部TestActivity引用瓦糟。
解決方案:

  • 如果消息是延時(shí)發(fā)送(sendMessageDelay),Handler 里面的消息還沒(méi)發(fā)送完畢的話赴蝇,Activity 的內(nèi)存也不會(huì)被回收菩浙,需要移除消息。

  • 改用靜態(tài)內(nèi)部類或外部類句伶。同時(shí)因?yàn)槭褂肏andler一般在收到消息后需要與Activity交互劲蜻,此時(shí)可以使用Activity的弱引用。

public class TestActivity extends Activity {
    private Handler mHandler = new MyHandler(this);

    //移除消息
    @Override
    onDestroy() {
        mHandler.removeCallbacksAndMessages(null)
    }

    //靜態(tài)內(nèi)部類
    static class MyHandler extends Handler {
        //弱引用持有Activity
        private WeakReference<Activity> mReference;

        public MyHandler(Activity activity) {
            mReference = new WeakReference<Activity>(activity);
        }

        @Override
        public void handleMessage(Message msg) {
            final Activity activity = mWeakReference.get();
        }
    }
}

4. 集合持有子元素

集合會(huì)持有子元素引用考余,如果子元素屬于無(wú)用對(duì)象先嬉,應(yīng)該及時(shí)從集合清除


5. 資源沒(méi)有及時(shí)關(guān)閉

在使用完File,Cursor,Stream,Bitmap等資源時(shí),要及時(shí)關(guān)閉釋放內(nèi)存秃殉。


6. Rxjava內(nèi)存泄漏

通常使用RxJava做網(wǎng)絡(luò)加載時(shí)線程調(diào)度坝初,很可能由于子線程未執(zhí)行 完畢導(dǎo)致內(nèi)存泄漏浸剩。
解決方案:

  • 使用CompositeDisposable管理
class Presenter  {
    private CompositeDisposable mDispose;
    //訂閱事件天機(jī)到CompositeDisposable
    private void addDispose(Disposable disposable) {
        if(mDispose== null){
            mDispose =new  CompositeDisposable();
        }
        mDispose.add(disposable);
    }
    
    //生命周期結(jié)束前調(diào)用dispose方法
    @Override
    public void unbind(){
        super.unbind();
        mDispose.dispose();
        mDispose = null;
    }
    
    //測(cè)試
    public void funcTest() {
        addDispose(Observable.just(1)
                .subscribeWith(observer..));
    }
    
}

7. MVP模式內(nèi)存泄漏

由于P層V層相互持有引用钾军,因此在V層(通常是Activity、Fragment等)生命周期結(jié)束前(如Activity.onDestroy時(shí))需要解除綁定


總結(jié)

內(nèi)存泄漏重點(diǎn)是無(wú)用的對(duì)象被生命周期較長(zhǎng)的對(duì)象引用導(dǎo)致GC時(shí)無(wú)法釋放绢要。
解決的辦法主要是從

    1. 短生命周期周期對(duì)象盡量避免持有長(zhǎng)生命周期對(duì)象引用
    1. 必須持有的吏恭,及時(shí)移除對(duì)長(zhǎng)生命周期對(duì)象的引用
    1. 利用弱引用的特性
    1. 及時(shí)關(guān)閉Cursor、File等資源
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末重罪,一起剝皮案震驚了整個(gè)濱河市樱哼,隨后出現(xiàn)的幾起案子哀九,更是在濱河造成了極大的恐慌,老刑警劉巖搅幅,帶你破解...
    沈念sama閱讀 218,451評(píng)論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件阅束,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡茄唐,警方通過(guò)查閱死者的電腦和手機(jī)息裸,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,172評(píng)論 3 394
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)沪编,“玉大人呼盆,你說(shuō)我怎么就攤上這事∫侠” “怎么了访圃?”我有些...
    開(kāi)封第一講書人閱讀 164,782評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)相嵌。 經(jīng)常有香客問(wèn)我腿时,道長(zhǎng),這世上最難降的妖魔是什么平绩? 我笑而不...
    開(kāi)封第一講書人閱讀 58,709評(píng)論 1 294
  • 正文 為了忘掉前任圈匆,我火速辦了婚禮,結(jié)果婚禮上捏雌,老公的妹妹穿的比我還像新娘跃赚。我一直安慰自己,他們只是感情好性湿,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,733評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布纬傲。 她就那樣靜靜地躺著,像睡著了一般肤频。 火紅的嫁衣襯著肌膚如雪叹括。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書人閱讀 51,578評(píng)論 1 305
  • 那天宵荒,我揣著相機(jī)與錄音汁雷,去河邊找鬼。 笑死报咳,一個(gè)胖子當(dāng)著我的面吹牛侠讯,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播暑刃,決...
    沈念sama閱讀 40,320評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼厢漩,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了岩臣?” 一聲冷哼從身側(cè)響起溜嗜,我...
    開(kāi)封第一講書人閱讀 39,241評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤宵膨,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后炸宵,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體辟躏,經(jīng)...
    沈念sama閱讀 45,686評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,878評(píng)論 3 336
  • 正文 我和宋清朗相戀三年土全,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了鸿脓。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,992評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡涯曲,死狀恐怖野哭,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情幻件,我是刑警寧澤拨黔,帶...
    沈念sama閱讀 35,715評(píng)論 5 346
  • 正文 年R本政府宣布,位于F島的核電站绰沥,受9級(jí)特大地震影響篱蝇,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜徽曲,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,336評(píng)論 3 330
  • 文/蒙蒙 一零截、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧秃臣,春花似錦涧衙、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書人閱讀 31,912評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至稚虎,卻和暖如春撤嫩,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背蠢终。 一陣腳步聲響...
    開(kāi)封第一講書人閱讀 33,040評(píng)論 1 270
  • 我被黑心中介騙來(lái)泰國(guó)打工序攘, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人寻拂。 一個(gè)月前我還...
    沈念sama閱讀 48,173評(píng)論 3 370
  • 正文 我出身青樓程奠,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親兜喻。 傳聞我的和親對(duì)象是個(gè)殘疾皇子梦染,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,947評(píng)論 2 355