Android內(nèi)存泄漏個人理解與分析

今天整理一下關(guān)于內(nèi)存泄漏和優(yōu)化相關(guān)塑崖,這是個人最近心得贷腕,希望能夠幫助讀者侵俗。

下面我們便開始吧。

最近組內(nèi)在討論關(guān)于內(nèi)存泄漏與優(yōu)化的問題丰刊,每個人多多少少可能都會遇到這樣的問題隘谣,總是覺得哪里會出現(xiàn)內(nèi)存泄漏,而網(wǎng)上對內(nèi)存泄漏和優(yōu)化的文章有一大堆啄巧,每次看的總是覺得一時能夠理解寻歧,但是自己卻總是用不到或者想不透,最近頗有心得秩仆,下面來講下關(guān)于這個問題码泛,結(jié)合一些例子,優(yōu)化和泄漏放在一起澄耍。

個人理解有以下幾點(diǎn):
1.首先噪珊,關(guān)于后臺服務(wù),別總是想著要逼肓活痢站,現(xiàn)在Google已經(jīng)把a(bǔ)pp后臺活動限制的死死的,別想著要反著來选酗,人家這樣做肯定是經(jīng)過仔細(xì)考慮才發(fā)布的阵难,而且每個版本都還要加強(qiáng)限制,不懂得小伙伴可以大概了解一下Doze模式下面程序活動情況芒填,基本后臺活動會不斷延時進(jìn)行呜叫,就連用的微信最近放久了也不及時不靈光了空繁。
結(jié)論:服務(wù)Google推薦使用JobService,一般服務(wù)做前臺就行朱庆,也可以用IntentService(如果與UI無交互)

2.應(yīng)用返回為殺死盛泡,我們經(jīng)常會在主頁面重寫返回,讓用戶點(diǎn)了back之后進(jìn)入后臺頁面椎工,這是不友好的饭于。
建議:使用正常退出流程,讓應(yīng)用關(guān)閉當(dāng)前頁面维蒙,否則這部分頁面任然占用內(nèi)存掰吕,導(dǎo)致資源浪費(fèi)

3.關(guān)于Context引用,有Activity的Context颅痊,而一般建議使用ApplicationContext殖熟,這樣使對象引用的是Application,而不是頁面的Context斑响,否則存在內(nèi)存泄漏菱属,這個通俗易懂,但是什么情況是Context引用而容易導(dǎo)致內(nèi)存泄漏呢舰罚,我整理了一下纽门,用一句話來講:線程或者靜態(tài)對象直接或者間接引用了ActivityContext。

什么是直接引用营罢?

1.靜態(tài)對象引用

public class MainActivity extends Activity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
     //public static Object ref1;
        RefManager.ref1 = this;
    }
}

這是一個靜態(tài)對象引用case赏陵,這里存在頁面關(guān)閉activity任然被靜態(tài)指向?qū)е聝?nèi)存泄漏,我想這樣的代碼應(yīng)該每人寫饲漾。

2.線程引用

public class MyThread extends Thread{
    private Context mContext;

    public MyThread(Context mContext) {
        this.mContext = mContext;
    }
}

Thread mThread = new MyThread(this);
mThread.start();

這種case是線程直接引用Context蝙搔,這種情況導(dǎo)致頁面關(guān)閉但是Thread可能還沒有執(zhí)行完成導(dǎo)致Context被引用出現(xiàn)內(nèi)存泄漏。

以上是2種直接引用this對象(Map引用也差不多)考传,這2種情況都需要使用慎重吃型,直接引用很容易排查,建議使用WeakReference或者在頁面推出執(zhí)行引用置空操作并且釋放資源

3.間接引用:

關(guān)于間接引用僚楞,據(jù)我理解勤晚,其實就是 非靜態(tài)內(nèi)部類/匿名內(nèi)部類 被靜態(tài)或者線程引用,為什么這樣理解呢泉褐?

3.1鏈?zhǔn)絺鬟f引用:顧名思義运翼,就是一個A -> B -> T/S,那么T/S也是引用A的兴枯,舉例如下:

MyObject obj = new MyObject(MainActivity.this);
Thread mThread = new MyThread(obj);
mThread.start();

這里MyObject對象對Activity引用血淌,而該對象又被MyThread引用,這么按照傳遞的效果,那么Activity也是間接被MyThread引用了

3.2非靜態(tài)內(nèi)部類:

非靜態(tài)內(nèi)部類可以訪問外部方法(靜態(tài)內(nèi)部類則不能訪問)悠夯,也就是說癌淮,非靜態(tài)內(nèi)部類默認(rèn)可以完全訪問外部方法,這樣外部類就是默認(rèn)被非靜態(tài)內(nèi)部類完全引用了沦补,如果將這個非靜態(tài)內(nèi)部類傳給靜態(tài)變量或者線程乳蓄,那么就好比 A -> B -> T/S , 其中A是Context/Activity,B在A里面屬于非靜態(tài)內(nèi)部類夕膀, T/S是線程或靜態(tài)變量虚倒,這樣T/S就是間接引用A,在A關(guān)閉可以導(dǎo)致內(nèi)存泄漏产舞,當(dāng)然了魂奥,這里需要注意的是可能B經(jīng)過很多C或者D或者E,最后到T/S易猫,這就存在一個鏈?zhǔn)介g接引用耻煤,這條鏈上面的每個元素都不會被釋放,導(dǎo)致泄漏准颓。下面將結(jié)合3.3舉例:

3.3匿名內(nèi)部類:

匿名內(nèi)部類同3.2非靜態(tài)內(nèi)部類哈蝇,匿名內(nèi)部類是由new創(chuàng)建并重寫或者實現(xiàn)某個方法,假設(shè)在A中有個匿名內(nèi)部類攘已,那么匿名內(nèi)部類重寫或者實現(xiàn)的方法中可以調(diào)用A中所有方法炮赦,這就存在對A的引用,匿名內(nèi)部類引用了A样勃,這時候又和上面一樣的case了眼五,如果這個匿名內(nèi)部類經(jīng)過多次鏈?zhǔn)絺鬟f給了靜態(tài)變量或者線程,那么頁面關(guān)閉的時候彤灶,匿名內(nèi)部類不會被釋放,那么引用的A也不會被釋放批旺,導(dǎo)致內(nèi)存泄漏幌陕,常見的有CallBack,Handler汽煮,new構(gòu)造的所有對象重寫或?qū)崿F(xiàn)的方法會產(chǎn)生引用A內(nèi)部方法搏熄,舉個栗子:

public class MainActivity extends Activity{

    private void init(){
        //匿名內(nèi)部類引用
        MyThread thread = new MyThread(new callBack1() {
            @Override
            public void onResult() {
                processResult();
            }
        });
        //非靜態(tài)內(nèi)部類引用
        thread.setCallBack2(new callBack2());
    }

    public interface callBack1{
        void onResult();
    }

    public class callBack2{
        public void invoke(){
            MainActivity.this.processResult();
        }
    }

    public void processResult(){
        //do something
    }
}

此例子是一個Activity里面有一個內(nèi)部類CallBack2和一個接口,首先是非靜態(tài)內(nèi)部類暇赤,使用invoke方法調(diào)用Activity的onResult心例,其二是匿名內(nèi)部類接口callBack1,這里內(nèi)部類接口callBack1引用了this里面方法導(dǎo)致后臺操作不會及時釋放Context鞋囊。

4.資源的打開與關(guān)閉

使用IO止后、File流或者Sqlite、Cursor等資源時要及時關(guān)閉,一般都是對應(yīng)寫注冊與反注冊, Open與Close译株。

5.其他

耗時任務(wù)瓜喇,屬性動畫間接引用View里面Context,Thread(Runnable)歉糜,Timer引用This方法導(dǎo)致泄漏乘寒。

總結(jié):
關(guān)于內(nèi)存泄漏,目前個人理解就是對頁面Context(this)的引用匪补,直接或者間接引用伞辛,直接引用容易發(fā)現(xiàn),間接引用需要追蹤鏈接夯缺,不管是線程還是靜態(tài)內(nèi)部類蚤氏,引用方法或者view都會造成內(nèi)存泄漏。如果內(nèi)部類并沒有引用Context(this)里面的方法或者指向則不會造成泄漏喳逛。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末瞧捌,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子润文,更是在濱河造成了極大的恐慌姐呐,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,858評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件典蝌,死亡現(xiàn)場離奇詭異曙砂,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)骏掀,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,372評論 3 395
  • 文/潘曉璐 我一進(jìn)店門鸠澈,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人截驮,你說我怎么就攤上這事笑陈。” “怎么了葵袭?”我有些...
    開封第一講書人閱讀 165,282評論 0 356
  • 文/不壞的土叔 我叫張陵涵妥,是天一觀的道長。 經(jīng)常有香客問我坡锡,道長蓬网,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,842評論 1 295
  • 正文 為了忘掉前任鹉勒,我火速辦了婚禮帆锋,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘禽额。我一直安慰自己锯厢,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,857評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著哲鸳,像睡著了一般臣疑。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上徙菠,一...
    開封第一講書人閱讀 51,679評論 1 305
  • 那天讯沈,我揣著相機(jī)與錄音,去河邊找鬼婿奔。 笑死缺狠,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的萍摊。 我是一名探鬼主播挤茄,決...
    沈念sama閱讀 40,406評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼冰木!你這毒婦竟也來了穷劈?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,311評論 0 276
  • 序言:老撾萬榮一對情侶失蹤踊沸,失蹤者是張志新(化名)和其女友劉穎歇终,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體逼龟,經(jīng)...
    沈念sama閱讀 45,767評論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡评凝,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,945評論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了腺律。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片奕短。...
    茶點(diǎn)故事閱讀 40,090評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖匀钧,靈堂內(nèi)的尸體忽然破棺而出翎碑,到底是詐尸還是另有隱情,我是刑警寧澤之斯,帶...
    沈念sama閱讀 35,785評論 5 346
  • 正文 年R本政府宣布日杈,位于F島的核電站,受9級特大地震影響吊圾,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜翰蠢,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,420評論 3 331
  • 文/蒙蒙 一项乒、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧梁沧,春花似錦檀何、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,988評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽栓辜。三九已至,卻和暖如春垛孔,著一層夾襖步出監(jiān)牢的瞬間藕甩,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,101評論 1 271
  • 我被黑心中介騙來泰國打工周荐, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留狭莱,地道東北人。 一個月前我還...
    沈念sama閱讀 48,298評論 3 372
  • 正文 我出身青樓概作,卻偏偏與公主長得像腋妙,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子讯榕,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,033評論 2 355

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

  • Android 內(nèi)存管理的目的 內(nèi)存管理的目的就是讓我們在開發(fā)中怎么有效的避免我們的應(yīng)用出現(xiàn)內(nèi)存泄漏的問題骤素。簡單粗...
    晨光光閱讀 1,294評論 1 4
  • 內(nèi)存管理的目的就是讓我們在開發(fā)中怎么有效的避免我們的應(yīng)用出現(xiàn)內(nèi)存泄漏的問題。內(nèi)存泄漏大家都不陌生了愚屁,簡單粗俗的講济竹,...
    宇宙只有巴掌大閱讀 2,363評論 0 12
  • Android 內(nèi)存泄漏總結(jié) 內(nèi)存管理的目的就是讓我們在開發(fā)中怎么有效的避免我們的應(yīng)用出現(xiàn)內(nèi)存泄漏的問題。內(nèi)存泄漏...
    _痞子閱讀 1,637評論 0 8
  • Android 內(nèi)存泄漏總結(jié) 內(nèi)存管理的目的就是讓我們在開發(fā)中怎么有效的避免我們的應(yīng)用出現(xiàn)內(nèi)存泄漏的問題集绰。內(nèi)存泄漏...
    apkcore閱讀 1,221評論 2 7
  • 新家搬到了高樓规辱, 發(fā)現(xiàn)習(xí)慣住在平地上。 黃昏時打開了窗栽燕, 晚風(fēng)竟來得猝不及防罕袋。 我俯瞰著窗外的廣場, 花園里有人遛...
    遇上音階閱讀 282評論 0 0