android內存泄漏 OOM查找總結

本篇文章已授權微信公眾號 guolin_blog (郭霖)獨家發(fā)布

前言

先通俗理解下內存泄漏女责,內存溢出耳鸯,OOM湿蛔,GC回收這幾個概念。
把app的堆內存空間想成了一個杯子县爬,內存就是里面的水阳啥。
當你的app啟動后,系統(tǒng)會分配給app一個堆空間财喳,起始不會很大比如是32M(根據(jù)你的app啟動時的內存申請為準)


image.png
  • 隨著程序的運行對象的創(chuàng)建越來越多察迟,系統(tǒng)不斷加內存分配:32M -> 64M -> ...
  • 而GC回收則會定時掃描內存斩狱,發(fā)現(xiàn)不被引用的對象即可回收。
    正常來說你的app堆內存會有升有降扎瓶。
    此時如果有某個Activity持有某個引用所踊,在onDestroy時還不把這個引用設為null,那么返回進入退出這個界面概荷,Activity就會創(chuàng)建很多次從而存在多個實例秕岛,導致堆內存直升不降!這就叫做內存泄漏误证。

當用戶重復這個操作或者有多個不同Activity內存泄漏時继薛,app運行一段時間堆內存超過系統(tǒng)規(guī)定的最大值 heapSize,杯子滿了就會發(fā)現(xiàn)內存溢出(OOM)雷厂,app崩潰惋增。

關鍵點

通過上面這個例子,我們知道查找內存泄漏有如下幾點關鍵點:

  1. 如何知道你的app上限值heapSize是多少
  2. 什么情況導致無法GC
  3. 怎么復現(xiàn)是哪個界面內存泄漏
    下面通過一個實例來演示改鲫,如何借助AndroidStudio查找內存泄漏:

內存泄漏實例

當你的app在使用中莫名崩潰,如果是OOM那么會有如下日志:


image.png

接下來我們用下面的代碼獲取heapsize:

ActivityManager manager = (ActivityManager)getSystemService(Context.ACTIVITY_SERVICE);
int heapSize = manager.getMemoryClass();
int maxHeapSize = manager.getLargeMemoryClass();  // manafest.xml   android:largeHeap="true"
  • heapSize是設備分配給app的最大堆內存
  • maxHeapSize 是當配置了android:largeHeap="true" 才有的最大堆內存林束,一般是heapSize的2-3倍
    以HTC ONE為例像棘,兩個值分別是: 192M和512M。這里我只關注192M壶冒,maxHeapSize放到后面再說缕题。然后嘗試復現(xiàn)問題,手機連接AndroidStudio打開monitor胖腾,反復進入/退出懷疑內存泄漏的界面:


    image.png

    如果發(fā)現(xiàn)內存一直上升烟零,并且到接近192M的時候不動了,此時已經OOM只不過不一定會崩潰(oom異诚套鳎可以try catch)

  • 接著锨阿,用AndroidStudio自帶的內存分析工具分析,點擊Dump Java Heap:


    image.png

(備注:ViewDefectPhotoActivity是我的app里面一個界面记罚,用ViewPager展示墅诡,ImageLoader加載很多照片)

會在代碼區(qū) 生成當前時間點的 .hprof格式文件,里面當前的每個對象 內存占用情況桐智,我們現(xiàn)在懷疑ViewDefectPhotoActivity 可能內存泄漏 看一下:ViewDefectPhotoActivity 確實占用了很高的內存 而且有8個實例化對象,足以證明它有內存泄漏末早,隨便點擊其中一個,發(fā)現(xiàn)都和EditDefectActivity的內部類 ShowEditDefectHelper有關说庭。而且ShowEditDefectHelpe前面帶有 黃藍三角樹 這個圖標表示然磷,他可以被GC訪問到,也就是無法回收:


image.png

接下來看看ShowEditDefectHelper這個對象持有什么引用刊驴,右鍵點擊 Go To Instance:


image.png

發(fā)現(xiàn)這個內部類也被實例化多次姿搜,隨便點擊一個,發(fā)現(xiàn)屬于EventBus的引用 ,并且EventBus帶有黃藍圖標痪欲,那么問題就大概找到了悦穿,因為EventBus一直持有這個內部類的引用,導致這個內部類無法被回收业踢,而這個內部類持有ViewDefectPhotoActivity引用栗柒,導致ViewDefectPhotoActivity無法被回收 這個界面有很多圖片資源 當實例化7,8次之后 出現(xiàn)了OOM。
知举!

EventBus是用于事件通知的開源庫瞬沦,應該很多人都了解。它需要在某個類里面綁定和解綁定雇锡,我這里是在ShowEditDefectHelper注冊的逛钻,看下Activity的內部類ShowEditDefectHelper:


image.png

解釋下這里的邏輯:進入這個activity我會顯示一個進度條,請求網絡數(shù)據(jù)锰提,用戶可以隨時取消進度條曙痘。然后onCancel里面對EventBus解綁定:
但是這里有個低級錯誤:EventBus.getDefult().unregister(this)傳入的this是onCancelled()的匿名內部類而不是ShowEditDefectHelper.class導致EventBus無法解綁!
!
所以應該這么解綁:
EventBus.getDefult().unregister(ShowEditDefectHelper.Class);

立肘!
通過這個示例边坤,我們回答了上面前兩個關鍵點:

  1. 如何知道你的app上限值heapSize是多少
  2. 什么情況導致無法GC
    第三個關鍵點:3. 怎么復現(xiàn)是哪個界面內存泄漏谅年。內存泄漏不是一眼就能看出來了茧痒,需要測試人員配合。當然還有一個辦法就是facebook的開源庫:leakcanary融蹂,具體使用我不多介紹了旺订。它是一個apk安裝在手機上可以直接列出內存泄漏的Activity,但是有一定誤報幾率:


    image.png

我更喜歡leakcanary + AndroidStudio的方式超燃,精確無誤地找出問題区拳。

怎么避免內存

一句話歸納:(生命周期比Activity長的類不要去強引用Activity)

  1. 內部類請使用static,因為非靜態(tài)內部類默認持有外部類的引用淋纲,比如在Activity里面直接放一個自定義的Adapter

  2. 靜態(tài)類(比如Application劳闹,單例類,其他static類)請不要持有Activity引用洽瞬,因為靜態(tài)類生命周期比Activity長本涕。解決辦法:在需要的地方用BaseApplication.getTopActivity』锴裕或者Activity作為弱引用傳入

  3. 注意Handler會默認持有當前Activity菩颖,用的時候最好不要直接new Handler().post(new Runnable...),除非你確定這個runnable會在Activity銷毀前執(zhí)行完

OK,假設你的項目比較緊急为障,想暫時規(guī)避內存泄漏問題怎么辦晦闰?可以在manifest.xml加入本文開頭給的那個設置:

android:largeHeap="true"

此時heapsize會增大2-3倍放祟,緩解OOM的發(fā)生,但是技術債終究要還的呻右。希望大家認真揣摩本文用AndroidStudio分析泄漏的方法跪妥,而不是過分依賴leakcanary這個開源庫。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末声滥,一起剝皮案震驚了整個濱河市眉撵,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌落塑,老刑警劉巖纽疟,帶你破解...
    沈念sama閱讀 206,968評論 6 482
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異憾赁,居然都是意外死亡污朽,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,601評論 2 382
  • 文/潘曉璐 我一進店門龙考,熙熙樓的掌柜王于貴愁眉苦臉地迎上來蟆肆,“玉大人,你說我怎么就攤上這事洲愤⊥前牛” “怎么了?”我有些...
    開封第一講書人閱讀 153,220評論 0 344
  • 文/不壞的土叔 我叫張陵柬赐,是天一觀的道長。 經常有香客問我官紫,道長肛宋,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,416評論 1 279
  • 正文 為了忘掉前任束世,我火速辦了婚禮酝陈,結果婚禮上,老公的妹妹穿的比我還像新娘毁涉。我一直安慰自己沉帮,他們只是感情好,可當我...
    茶點故事閱讀 64,425評論 5 374
  • 文/花漫 我一把揭開白布贫堰。 她就那樣靜靜地躺著穆壕,像睡著了一般。 火紅的嫁衣襯著肌膚如雪其屏。 梳的紋絲不亂的頭發(fā)上喇勋,一...
    開封第一講書人閱讀 49,144評論 1 285
  • 那天,我揣著相機與錄音偎行,去河邊找鬼川背。 笑死贰拿,一個胖子當著我的面吹牛,可吹牛的內容都是我干的熄云。 我是一名探鬼主播膨更,決...
    沈念sama閱讀 38,432評論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼缴允!你這毒婦竟也來了荚守?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 37,088評論 0 261
  • 序言:老撾萬榮一對情侶失蹤癌椿,失蹤者是張志新(化名)和其女友劉穎健蕊,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體踢俄,經...
    沈念sama閱讀 43,586評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡缩功,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 36,028評論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了都办。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片嫡锌。...
    茶點故事閱讀 38,137評論 1 334
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖琳钉,靈堂內的尸體忽然破棺而出势木,到底是詐尸還是另有隱情,我是刑警寧澤歌懒,帶...
    沈念sama閱讀 33,783評論 4 324
  • 正文 年R本政府宣布啦桌,位于F島的核電站,受9級特大地震影響及皂,放射性物質發(fā)生泄漏甫男。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,343評論 3 307
  • 文/蒙蒙 一验烧、第九天 我趴在偏房一處隱蔽的房頂上張望板驳。 院中可真熱鬧,春花似錦碍拆、人聲如沸若治。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,333評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽端幼。三九已至,卻和暖如春浩习,著一層夾襖步出監(jiān)牢的瞬間静暂,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,559評論 1 262
  • 我被黑心中介騙來泰國打工谱秽, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留洽蛀,地道東北人摹迷。 一個月前我還...
    沈念sama閱讀 45,595評論 2 355
  • 正文 我出身青樓,卻偏偏與公主長得像郊供,于是被迫代替她去往敵國和親峡碉。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 42,901評論 2 345

推薦閱讀更多精彩內容