Android應(yīng)用內(nèi)存泄露分析右莱、改善經(jīng)驗(yàn)總結(jié)

前言

通過這幾天對好幾個應(yīng)用的內(nèi)存泄露檢測和改善彻采,效果明顯:

  • 完全退出應(yīng)用時,手動觸發(fā)GC瘫拣,從原來占有內(nèi)存100多M降到低于20M亿絮;

  • 手動觸發(fā)GC后,通過adb shell dumpsys meminfo packagename -d查看Activity和View的數(shù)量也趨近于0了(沒有做到歸零是因?yàn)镾DK中存在內(nèi)存泄露拂铡,需要中間層去處理)壹无;

  • 發(fā)現(xiàn)了一個SDK中的內(nèi)存泄露(Android InputMethodManager 導(dǎo)致的內(nèi)存泄露及解決方案)葱绒;

  • 發(fā)現(xiàn)一個MTK Webview的內(nèi)存泄露(org.chromium.android_webview.AwPasswordHandler.java中private static AwPasswordHandler sInstance = null導(dǎo)致的內(nèi)存泄露)感帅。

從結(jié)果來看我分析和改善內(nèi)存泄露的方法是對的,這個過程并不復(fù)雜地淀,所以可以梳理總結(jié)出來作為分享失球。

原則

對于性能問題,分析和改善有必要遵循以下原則:

  • 一切看數(shù)據(jù)說話帮毁,不能跟著感覺走实苞,感覺哪有問題就去改,很有可能會適得其反烈疚;

  • 性能優(yōu)化是一個持續(xù)的過程黔牵,需要不斷地改善,不要想著一氣呵成爷肝;

  • 對于性能問題猾浦,不一定必須要改善,受限于架構(gòu)或者其它原因某些問題可能會很難改善灯抛,必須要先保證能用金赦,再才考慮好用。

  • 改善后一定要驗(yàn)證对嚼,任何一個地方的改動都需要驗(yàn)證夹抗,避免因?yàn)楦纳菩阅軉栴}導(dǎo)致其它的問題。

步驟

下面是我在針對內(nèi)存泄露這個性能問題上的解決步驟:

優(yōu)先處理常見的內(nèi)存泄露問題

首先解決常見的內(nèi)存泄露問題纵竖,這個過程可以借助Android Studio的Analyze-Inspect Code對代碼做靜態(tài)分析漠烧,常見的內(nèi)存泄露問題有:

  • 非靜態(tài)內(nèi)部類導(dǎo)致的內(nèi)存泄露杏愤,比如Handler已脓,解決方法是將內(nèi)部類寫成靜態(tài)內(nèi)部類声邦,在靜態(tài)內(nèi)部類中使用軟引用/弱引用持有外部類的實(shí)例摆舟,eg:

          static class ExerciseHandler extends Handler{
              private SoftReference<ExerciseActivity> exerciseActivitySoftReference = null;
    
              public ExerciseHandler(ExerciseActivity exerciseActivity){
                  exerciseActivitySoftReference = new SoftReference<ExerciseActivity>(exerciseActivity);
              }
      
              @Override
              public void handleMessage(Message msg) {
                  ExerciseActivity exerciseActivity = exerciseActivitySoftReference.get();
                  if(null != exerciseActivity){
                      super.handleMessage(msg);
                      switch (msg.what) {
                          case MSG_XX:
                              exerciseActivity.***;
                              break亥曹;
                          default:
                              break;
                      }
                  }
              }
          }
    
  • IO操作后,沒有關(guān)閉文件導(dǎo)致的內(nèi)存泄露恨诱,比如Cursor媳瞪、FileInputStream、FileOutputStream使用完后沒有關(guān)閉照宝,這種問題在Android Studio 2.0中能夠通過靜態(tài)代碼分析檢查出來蛇受,直接改善就可以了;

  • 自定義View中使用TypedArray后厕鹃,沒有recycle兢仰,這種問題也可以在Android Studio 2.0中能夠通過靜態(tài)代碼分析檢查出來,直接改善就可以了剂碴;

  • 某些地方使用了四大組件的context把将,在離開這些組件后仍然持有其context導(dǎo)致的內(nèi)存泄露,這種問題屬于共識忆矛,在編寫代碼的過程中就應(yīng)該按照規(guī)則來察蹲,使用Application的Context就可以解決這類內(nèi)存泄露的問題了,至于什么情況下應(yīng)該使用四大組件的Context催训,什么時候應(yīng)該使用Application的context可以參見下表:

    application使用場景

備注:大家注意看到有一些NO上添加了一些數(shù)字洽议,其實(shí)這些從能力上來說是YES,但是為什么說是NO呢漫拭?下面一個一個解釋:

1亚兄、數(shù)字1:啟動Activity在這些類中是可以的,但是需要創(chuàng)建一個新的task采驻,一般情況不推薦审胚;

2、數(shù)字2:在這些類中去layout inflate是合法的挑宠,但是會使用系統(tǒng)默認(rèn)的主題樣式菲盾,如果你自定義了某些樣式可能不會被使用;

3各淀、數(shù)字3:在Receiver為null時允許懒鉴,在4.2或以上的版本中,用于獲取黏性廣播的當(dāng)前值。(可以無視)临谱;

4璃俗、ContentProvider、BroadcastReceiver之所以在上述表格中悉默,是因?yàn)樵谄鋬?nèi)部方法中都有一個context用于使用城豁。
  • 還有一種不屬于內(nèi)存泄露,但在分析內(nèi)存泄露的問題時應(yīng)該一并解決:同一個APP抄课,將圖片放在不同的drawable文件夾下唱星,在相同的設(shè)備上占用的內(nèi)存情況不一樣,具體可以參見:關(guān)于Android中圖片大小跟磨、內(nèi)存占用與drawable文件夾關(guān)系的研究與分析间聊。解決這個問題遵循以下原則就可以了:

    1、UI只提供一套高分辨率的圖抵拘,圖片建議放在drawable-xxhdpi文件夾下(放在xxxhdpi或者更高分辨率的文件夾下沒有必要哎榴,權(quán)衡利弊,照顧主流設(shè)備即可)僵蛛,這樣在低分辨率設(shè)備中圖片的大小只是壓縮尚蝌,不會存在內(nèi)存增大的情況;

    2充尉、涉及到桌面插件或者不需要縮放的圖片飘言,放在drawable-nodpi文件夾下,這個文件夾下的圖片在任何設(shè)備上都是不會縮放的喉酌。

通過工具檢查程序運(yùn)行后的內(nèi)存泄露

通過上面的步驟热凹,應(yīng)用中的大部分內(nèi)存泄露問題都能夠得到解決泵喘,還有一些內(nèi)存泄露泪电,需要運(yùn)行程序,分析運(yùn)行后的內(nèi)存快照來解決纪铺,比如注冊之后沒有反注冊相速、類中的靜態(tài)成員變量導(dǎo)致的內(nèi)存泄露、SDK中的內(nèi)存泄露等鲜锚。解決這類問題可以分兩步進(jìn)行:

  • 通過內(nèi)存泄露檢測工具先定位是哪有問題突诬,內(nèi)存泄露的檢測有兩種比較便捷的方式:

    1、一種是使用開源項(xiàng)目Leakcanary芜繁,需要添加到代碼中旺隙,運(yùn)行后生成分析結(jié)果;

    2骏令、另一種方式是使用adb shell dumpsys meminfo packagename -d命令蔬捷,在進(jìn)入一個界面之前查看一遍Activity和View的數(shù)量,在退出這個界面之后再查看一遍Activity和View的數(shù)量,對比進(jìn)入前和進(jìn)入后Activity和View數(shù)量的變化情況周拐,如果有差異铡俐,則說明存在內(nèi)存泄露(在使用命令查看Activity和View的數(shù)量之前,記得手動觸發(fā)GC)妥粟。

    備注:在Android Studio中审丘,可以通過如下方式獲取當(dāng)前選中進(jìn)程的內(nèi)存信息:

  • 然后通過MAT取程序運(yùn)行時的內(nèi)存快照做詳細(xì)分析,對于MAT的使用勾给,網(wǎng)上有很多優(yōu)質(zhì)的文章滩报,比如:Android 性能優(yōu)化之使用MAT分析內(nèi)存泄露問題,在使用MAT前播急,有必要知道這幾點(diǎn):

    1露泊、 不要指望MAT明確告訴你哪里存在內(nèi)存泄露,這需要你根據(jù)上一步驟首先定位到可能存在內(nèi)存泄露的類旅择,然后借助MAT確認(rèn)是否真的存在內(nèi)存泄露惭笑,具體哪個地方存在內(nèi)存泄露;

    2生真、借助Retained Size分析某一個類及與之相關(guān)的實(shí)例所消耗的內(nèi)存沉噩,如果這個類的Retained Size比較大,優(yōu)先分析柱蟀;

    3川蒙、檢查某個類是否存在內(nèi)存泄露時,排除其軟/弱/虛引用长已,右鍵某個類→Merge Shortest Paths to GC Roots→exclude all phantom/weak/soft etc.references畜眨。

驗(yàn)證改善效果

根據(jù)個人經(jīng)驗(yàn),我一般是這樣驗(yàn)證改善效果的术瓮,運(yùn)行程序康聂,各個功能跑一遍,確保沒有改出問題胞四,完全退出程序恬汁,手動觸發(fā)GC,然后通過adb shell dumpsys meminfo packagename -d查看Activivites和Views的數(shù)量是否趨近于0辜伟;如果不是0氓侧,通過Leakcanary檢查可能存在內(nèi)存泄露的地方,繼續(xù)通過MAT分析导狡,周而復(fù)始约巷,改善到自己滿意為止。

推薦閱讀

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末旱捧,一起剝皮案震驚了整個濱河市独郎,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖囚聚,帶你破解...
    沈念sama閱讀 212,816評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件靖榕,死亡現(xiàn)場離奇詭異,居然都是意外死亡顽铸,警方通過查閱死者的電腦和手機(jī)茁计,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,729評論 3 385
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來谓松,“玉大人星压,你說我怎么就攤上這事」砥” “怎么了娜膘?”我有些...
    開封第一講書人閱讀 158,300評論 0 348
  • 文/不壞的土叔 我叫張陵,是天一觀的道長优质。 經(jīng)常有香客問我竣贪,道長,這世上最難降的妖魔是什么巩螃? 我笑而不...
    開封第一講書人閱讀 56,780評論 1 285
  • 正文 為了忘掉前任演怎,我火速辦了婚禮,結(jié)果婚禮上避乏,老公的妹妹穿的比我還像新娘爷耀。我一直安慰自己,他們只是感情好拍皮,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,890評論 6 385
  • 文/花漫 我一把揭開白布歹叮。 她就那樣靜靜地躺著,像睡著了一般铆帽。 火紅的嫁衣襯著肌膚如雪咆耿。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 50,084評論 1 291
  • 那天锄贼,我揣著相機(jī)與錄音票灰,去河邊找鬼。 笑死宅荤,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的浸策。 我是一名探鬼主播冯键,決...
    沈念sama閱讀 39,151評論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼庸汗!你這毒婦竟也來了惫确?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,912評論 0 268
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎改化,沒想到半個月后掩蛤,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,355評論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡陈肛,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,666評論 2 327
  • 正文 我和宋清朗相戀三年揍鸟,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片句旱。...
    茶點(diǎn)故事閱讀 38,809評論 1 341
  • 序言:一個原本活蹦亂跳的男人離奇死亡阳藻,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出谈撒,到底是詐尸還是另有隱情腥泥,我是刑警寧澤,帶...
    沈念sama閱讀 34,504評論 4 334
  • 正文 年R本政府宣布啃匿,位于F島的核電站蛔外,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏溯乒。R本人自食惡果不足惜冒萄,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 40,150評論 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望橙数。 院中可真熱鬧尊流,春花似錦、人聲如沸灯帮。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,882評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽钟哥。三九已至迎献,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間腻贰,已是汗流浹背吁恍。 一陣腳步聲響...
    開封第一講書人閱讀 32,121評論 1 267
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留播演,地道東北人冀瓦。 一個月前我還...
    沈念sama閱讀 46,628評論 2 362
  • 正文 我出身青樓,卻偏偏與公主長得像写烤,于是被迫代替她去往敵國和親翼闽。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,724評論 2 351

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