Android 內(nèi)存泄露優(yōu)化處理

參考:
Android應(yīng)用內(nèi)存泄露分析、改善經(jīng)驗(yàn)總結(jié)
使用新版Android Studio檢測(cè)內(nèi)存泄露和性能
解決安卓CPU使用率過高問題
Android CPU使用過大的問題解決以及造成的原因
AndroidStudio CPU Monitor使用介紹
Skipped 60 frames! The application may be doing too much work on its main thread

前言:
通過這幾天對(duì)好幾個(gè)應(yīng)用的內(nèi)存泄露檢測(cè)和改善超埋,效果明顯:
完全退出應(yīng)用時(shí),手動(dòng)觸發(fā)GC荔棉,從原來占有內(nèi)存100多M降到低于20M贱勃;
手動(dòng)觸發(fā)GC后,通過adb shell dumpsys meminfo packagename -d查看Activity和View的數(shù)量也趨近于0了(沒有做到歸零是因?yàn)镾DK中存在內(nèi)存泄露壕曼,需要中間層去處理)昼扛;
發(fā)現(xiàn)了一個(gè)SDK中的內(nèi)存泄露(Android InputMethodManager 導(dǎo)致的內(nèi)存泄露及解決方案)寸齐;
發(fā)現(xiàn)一個(gè)MTK Webview的內(nèi)存泄露(org.chromium.android_webview.AwPasswordHandler.java中private static AwPasswordHandler sInstance = null導(dǎo)致的內(nèi)存泄露)。

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

原則
對(duì)于性能問題蛹含,分析和改善有必要遵循以下原則:

  • 一切看數(shù)據(jù)說話毅厚,不能跟著感覺走,感覺哪有問題就去改浦箱,很有可能會(huì)適得其反吸耿;
  • 性能優(yōu)化是一個(gè)持續(xù)的過程,需要不斷地改善酷窥,不要想著一氣呵成咽安;
  • 對(duì)于性能問題,不一定必須要改善蓬推,受限于架構(gòu)或者其它原因某些問題可能會(huì)很難改善妆棒,必須要先保證能用,再才考慮好用。
  • 改善后一定要驗(yàn)證糕珊,任何一個(gè)地方的改動(dòng)都需要驗(yàn)證蛋铆,避免因?yàn)楦纳菩阅軉栴}導(dǎo)致其它的問題。
步驟

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

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

首先解決常見的內(nèi)存泄露問題放接,這個(gè)過程可以借助Android Studio的Analyze-Inspect Code對(duì)代碼做靜態(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)存泄露,這種問題屬于共識(shí)茶行,在編寫代碼的過程中就應(yīng)該按照規(guī)則來躯概,使用Application的Context就可以解決這類內(nèi)存泄露的問題了,至于什么情況下應(yīng)該使用四大組件的Context畔师,什么時(shí)候應(yīng)該使用Application的context可以參見下表:


    application使用場(chǎng)景

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

數(shù)字1:?jiǎn)?dòng)Activity在這些類中是可以的固蛾,但是需要?jiǎng)?chuàng)建一個(gè)新的task,一般情況不推薦度陆;
數(shù)字2:在這些類中去layout inflate是合法的艾凯,但是會(huì)使用系統(tǒng)默認(rèn)的主題樣式,如果你自定義了某些樣式可能不會(huì)被使用懂傀;
數(shù)字3:在Receiver為null時(shí)允許趾诗,在4.2或以上的版本中,用于獲取黏性廣播的當(dāng)前值。(可以無視)恃泪;
ContentProvider郑兴、BroadcastReceiver之所以在上述表格中,是因?yàn)樵谄鋬?nèi)部方法中都有一個(gè)context用于使用贝乎。

還有一種不屬于內(nèi)存泄露情连,但在分析內(nèi)存泄露的問題時(shí)應(yīng)該一并解決:同一個(gè)APP,將圖片放在不同的drawable文件夾下览效,在相同的設(shè)備上占用的內(nèi)存情況不一樣却舀,具體可以參見:關(guān)于Android中圖片大小、內(nèi)存占用與drawable文件夾關(guān)系的研究與分析锤灿。解決這個(gè)問題遵循以下原則就可以了:1挽拔、UI只提供一套高分辨率的圖,圖片建議放在drawable-xxhdpi文件夾下(放在xxxhdpi或者更高分辨率的文件夾下沒有必要但校,權(quán)衡利弊螃诅,照顧主流設(shè)備即可),這樣在低分辨率設(shè)備中圖片的大小只是壓縮状囱,不會(huì)存在內(nèi)存增大的情況术裸;2、涉及到桌面插件或者不需要縮放的圖片浪箭,放在drawable-nodpi文件夾下穗椅,這個(gè)文件夾下的圖片在任何設(shè)備上都是不會(huì)縮放的。

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

通過上面的步驟奶栖,應(yīng)用中的大部分內(nèi)存泄露問題都能夠得到解決匹表,還有一些內(nèi)存泄露,需要運(yùn)行程序宣鄙,分析運(yùn)行后的內(nèi)存快照來解決袍镀,比如注冊(cè)之后沒有反注冊(cè)、類中的靜態(tài)成員變量導(dǎo)致的內(nèi)存泄露冻晤、SDK中的內(nèi)存泄露等苇羡。解決這類問題可以分兩步進(jìn)行:

  • 通過內(nèi)存泄露檢測(cè)工具先定位是哪有問題,內(nèi)存泄露的檢測(cè)有兩種比較便捷的方式:1鼻弧、一種是使用開源項(xiàng)目Leakcanary设江,需要添加到代碼中,運(yùn)行后生成分析結(jié)果攘轩;2叉存、另一種方式是使用adb shell dumpsys meminfo packagename -d命令,在進(jìn)入一個(gè)界面之前查看一遍Activity和View的數(shù)量度帮,在退出這個(gè)界面之后再查看一遍Activity和View的數(shù)量歼捏,對(duì)比進(jìn)入前和進(jìn)入后Activity和View數(shù)量的變化情況稿存,如果有差異,則說明存在內(nèi)存泄露(在使用命令查看Activity和View的數(shù)量之前瞳秽,記得手動(dòng)觸發(fā)GC)瓣履。

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


然后通過MAT取程序運(yùn)行時(shí)的內(nèi)存快照做詳細(xì)分析练俐,對(duì)于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)存泄露念颈,具體哪個(gè)地方存在內(nèi)存泄露泉粉;2、借助Retained Size分析某一個(gè)類及與之相關(guān)的實(shí)例所消耗的內(nèi)存榴芳,如果這個(gè)類的Retained Size比較大嗡靡,優(yōu)先分析;3窟感、檢查某個(gè)類是否存在內(nèi)存泄露時(shí)讨彼,排除其軟/弱/虛引用,右鍵某個(gè)類→Merge Shortest Paths to GC Roots→exclude all phantom/weak/soft etc.references柿祈。

驗(yàn)證改善效果

根據(jù)個(gè)人經(jīng)驗(yàn)哈误,我一般是這樣驗(yàn)證改善效果的,運(yùn)行程序躏嚎,各個(gè)功能跑一遍蜜自,確保沒有改出問題,完全退出程序卢佣,手動(dòng)觸發(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)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市待笑,隨后出現(xiàn)的幾起案子鸣皂,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 211,265評(píng)論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件寞缝,死亡現(xiàn)場(chǎng)離奇詭異癌压,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)荆陆,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,078評(píng)論 2 385
  • 文/潘曉璐 我一進(jìn)店門滩届,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人被啼,你說我怎么就攤上這事帜消。” “怎么了浓体?”我有些...
    開封第一講書人閱讀 156,852評(píng)論 0 347
  • 文/不壞的土叔 我叫張陵泡挺,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我命浴,道長(zhǎng)娄猫,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,408評(píng)論 1 283
  • 正文 為了忘掉前任生闲,我火速辦了婚禮媳溺,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘碍讯。我一直安慰自己悬蔽,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,445評(píng)論 5 384
  • 文/花漫 我一把揭開白布捉兴。 她就那樣靜靜地躺著蝎困,像睡著了一般。 火紅的嫁衣襯著肌膚如雪倍啥。 梳的紋絲不亂的頭發(fā)上难衰,一...
    開封第一講書人閱讀 49,772評(píng)論 1 290
  • 那天,我揣著相機(jī)與錄音逗栽,去河邊找鬼盖袭。 笑死,一個(gè)胖子當(dāng)著我的面吹牛彼宠,可吹牛的內(nèi)容都是我干的鳄虱。 我是一名探鬼主播,決...
    沈念sama閱讀 38,921評(píng)論 3 406
  • 文/蒼蘭香墨 我猛地睜開眼凭峡,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼拙已!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起摧冀,我...
    開封第一講書人閱讀 37,688評(píng)論 0 266
  • 序言:老撾萬榮一對(duì)情侶失蹤倍踪,失蹤者是張志新(化名)和其女友劉穎系宫,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體建车,經(jīng)...
    沈念sama閱讀 44,130評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡扩借,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,467評(píng)論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了缤至。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片潮罪。...
    茶點(diǎn)故事閱讀 38,617評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖领斥,靈堂內(nèi)的尸體忽然破棺而出嫉到,到底是詐尸還是另有隱情,我是刑警寧澤月洛,帶...
    沈念sama閱讀 34,276評(píng)論 4 329
  • 正文 年R本政府宣布何恶,位于F島的核電站,受9級(jí)特大地震影響嚼黔,放射性物質(zhì)發(fā)生泄漏导而。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,882評(píng)論 3 312
  • 文/蒙蒙 一隔崎、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧韵丑,春花似錦爵卒、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,740評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至陌僵,卻和暖如春轴合,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背碗短。 一陣腳步聲響...
    開封第一講書人閱讀 31,967評(píng)論 1 265
  • 我被黑心中介騙來泰國(guó)打工受葛, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人偎谁。 一個(gè)月前我還...
    沈念sama閱讀 46,315評(píng)論 2 360
  • 正文 我出身青樓总滩,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親巡雨。 傳聞我的和親對(duì)象是個(gè)殘疾皇子闰渔,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,486評(píng)論 2 348

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