內(nèi)存泄露轉(zhuǎn)載

本文為LeakCanary: Detect all memory leaks!的翻譯。原文在: https://corner.squareup.com/2015/05/leak-canary.html

本文為轉(zhuǎn)載腌乡。

java.lang.OutOfMemoryError at android.graphics.Bitmap.nativeCreate(Bitmap.java:-2) at android.graphics.Bitmap.createBitmap(Bitmap.java:689) at com.squareup.ui.SignView.createSignatureBitmap(SignView.java:121)

誰(shuí)也不會(huì)喜歡 OutOfMemoryError

Square Register 中, 在簽名頁(yè)面盟劫,我們把客戶(hù)的簽名畫(huà)在 bitmap cache 上。 這個(gè) bitmap 的尺寸幾乎和屏幕的尺寸一樣大与纽,在創(chuàng)建這個(gè) bitmap 對(duì)象時(shí)侣签,經(jīng)常會(huì)引發(fā) OutOfMemoryError
,簡(jiǎn)稱(chēng)OOM
急迂。

當(dāng)時(shí)影所,我們嘗試過(guò)一些解決方案,但都沒(méi)解決問(wèn)題
使用 Bitmap.Config.ALPHA_8 因?yàn)榱潘椋灻麅H有黑色猴娩。

捕捉 OutOfMemoryError
, 嘗試 GC 并重試(受 GCUtils 啟發(fā))。

我們沒(méi)想過(guò)在 Java heap 內(nèi)存之外創(chuàng)建 bitmap 勺阐【碇校苦逼的我們,那會(huì) Fresco 還不存在渊抽。

路子走錯(cuò)了
其實(shí) bitmap 的尺寸不是真正的問(wèn)題蟆豫,當(dāng)內(nèi)存吃緊的時(shí)候,到處都有可能引發(fā) OO腰吟。在創(chuàng)建大對(duì)象无埃,比如 bitmap 的時(shí)候,更有可能發(fā)生毛雇。OOM 只是一個(gè)表象嫉称,更深層次的問(wèn)題可能是: 內(nèi)存泄露
什么是內(nèi)存泄露
一些對(duì)象有著有限的生命周期灵疮。當(dāng)這些對(duì)象所要做的事情完成了织阅,我們希望他們會(huì)被回收掉。但是如果有一系列對(duì)這個(gè)對(duì)象的引用震捣,那么在我們期待這個(gè)對(duì)象生命周期結(jié)束的時(shí)候被收回的時(shí)候荔棉,它是不會(huì)被回收的。它還會(huì)占用內(nèi)存蒿赢,這就造成了內(nèi)存泄露润樱。持續(xù)累加,內(nèi)存很快被耗盡羡棵。
比如壹若,當(dāng) Activity.onDestroy
被調(diào)用之后,activity 以及它涉及到的 view 和相關(guān)的 bitmap 都應(yīng)該被回收。但是店展,如果有一個(gè)后臺(tái)線(xiàn)程持有這個(gè) activity 的引用月褥,那么 activity 對(duì)應(yīng)的內(nèi)存就不能被回收台妆。這最終將會(huì)導(dǎo)致內(nèi)存耗盡,然后因?yàn)?OOM 而 crash。
對(duì)戰(zhàn)內(nèi)存泄露
排查內(nèi)存泄露是一個(gè)全手工的過(guò)程惑芭,這在 Raizlabs 的 Wrangling Dalvik 系列文章中有詳細(xì)描述盅安。
以下幾個(gè)關(guān)鍵步驟:
通過(guò) Bugsnag, Crashlytics 或者 Developer Console 等統(tǒng)計(jì)平臺(tái)面殖,了解 OutOfMemoryError
情況震缭。

重現(xiàn)問(wèn)題。為了重現(xiàn)問(wèn)題席怪,機(jī)型非常重要应闯,因?yàn)橐恍﹩?wèn)題只在特定的設(shè)備上會(huì)出現(xiàn)。為了找到特定的機(jī)型挂捻,你需要想盡一切辦法碉纺,你可能需要去買(mǎi),去借刻撒,甚至去偷骨田。 當(dāng)然,為了確定復(fù)現(xiàn)步驟声怔,你需要一遍一遍地去嘗試态贤。一切都是非常原始和粗暴的。

在發(fā)生內(nèi)存泄露的時(shí)候醋火,把內(nèi)存 Dump 出來(lái)悠汽。具體看這里

然后芥驳,你需要在 MAT 或者 YourKit 之類(lèi)的內(nèi)存分析工具中反復(fù)查看柿冲,找到那些原本該被回收掉的對(duì)象。

計(jì)算這個(gè)對(duì)象到 GC roots 的最短強(qiáng)引用路徑兆旬。

確定引用路徑中的哪個(gè)引用是不該有的假抄,然后修復(fù)問(wèn)題。

很復(fù)雜對(duì)吧丽猬?
如果有一個(gè)類(lèi)庫(kù)能在發(fā)生 OOM 之前把這些事情全部都搞定宿饱,然后你只要修復(fù)這些問(wèn)題就好了,豈不妙哉脚祟!
LeakCanary
LeakCanary 是一個(gè)檢測(cè)內(nèi)存泄露的開(kāi)源類(lèi)庫(kù)谬以。你可以在 debug 包種輕松檢測(cè)內(nèi)存泄露。
先看一個(gè)例子:
class Cat {}class Box { Cat hiddenCat;}class Docker { // 靜態(tài)變量由桌,將不會(huì)被回收为黎,除非加載 Docker 類(lèi)的 ClassLoader 被回收胡陪。 static Box container;}// ...Box box = new Box();// 薛定諤之貓Cat schrodingerCat = new Cat();box.hiddenCat = schrodingerCat;Docker.container = box;

創(chuàng)建一個(gè)RefWatcher
,監(jiān)控對(duì)象引用情況碍舍。
// 我們期待薛定諤之貓很快就會(huì)消失(或者不消失),我們監(jiān)控一下refWatcher.watch(schrodingerCat);

當(dāng)發(fā)現(xiàn)有內(nèi)存泄露的時(shí)候邑雅,你會(huì)看到一個(gè)很漂亮的 leak trace 報(bào)告:
GC ROOT static Docker.container
references Box.hiddenCat
leaks Cat instance

我們知道片橡,你很忙,每天都有一大堆需求淮野。所以我們把這個(gè)事情弄得很簡(jiǎn)單捧书,你只需要添加一行代碼就行了。然后 LeakCanary 就會(huì)自動(dòng)偵測(cè) activity 的內(nèi)存泄露了骤星。
public class ExampleApplication extends Application { @Override public void onCreate() { super.onCreate(); LeakCanary.install(this); }}

然后你會(huì)在通知欄看到這樣很漂亮的一個(gè)界面:


結(jié)論
使用 LeakCanary 之后经瓷,我們修復(fù)了我們 APP 中相當(dāng)多的內(nèi)存泄露。我們甚至發(fā)現(xiàn)了 Android SDK 中的一些內(nèi)存泄露問(wèn)題洞难。
結(jié)果是驚艷的舆吮,我們減少了 94% 的由 OOM 導(dǎo)致的 crash。

如果你也想消滅 OOM crash队贱,那還猶豫什么色冀,趕快使用 LeakCanary
相關(guān)鏈接:
LeakCanary 中文使用說(shuō)明

一個(gè)非常簡(jiǎn)單的 LeakCanary demo: https://github.com/liaohuqiu/leakcanary-demo

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市柱嫌,隨后出現(xiàn)的幾起案子锋恬,更是在濱河造成了極大的恐慌,老刑警劉巖编丘,帶你破解...
    沈念sama閱讀 218,546評(píng)論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件与学,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡嘉抓,警方通過(guò)查閱死者的電腦和手機(jī)索守,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,224評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)掌眠,“玉大人蕾盯,你說(shuō)我怎么就攤上這事±侗” “怎么了级遭?”我有些...
    開(kāi)封第一講書(shū)人閱讀 164,911評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀(guān)的道長(zhǎng)渺尘。 經(jīng)常有香客問(wèn)我挫鸽,道長(zhǎng),這世上最難降的妖魔是什么鸥跟? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,737評(píng)論 1 294
  • 正文 為了忘掉前任丢郊,我火速辦了婚禮盔沫,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘枫匾。我一直安慰自己架诞,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,753評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布干茉。 她就那樣靜靜地躺著谴忧,像睡著了一般。 火紅的嫁衣襯著肌膚如雪角虫。 梳的紋絲不亂的頭發(fā)上沾谓,一...
    開(kāi)封第一講書(shū)人閱讀 51,598評(píng)論 1 305
  • 那天,我揣著相機(jī)與錄音戳鹅,去河邊找鬼均驶。 笑死,一個(gè)胖子當(dāng)著我的面吹牛枫虏,可吹牛的內(nèi)容都是我干的妇穴。 我是一名探鬼主播,決...
    沈念sama閱讀 40,338評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼隶债,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼伟骨!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起燃异,我...
    開(kāi)封第一講書(shū)人閱讀 39,249評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤携狭,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后回俐,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體逛腿,經(jīng)...
    沈念sama閱讀 45,696評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,888評(píng)論 3 336
  • 正文 我和宋清朗相戀三年仅颇,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了单默。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,013評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡忘瓦,死狀恐怖搁廓,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情耕皮,我是刑警寧澤境蜕,帶...
    沈念sama閱讀 35,731評(píng)論 5 346
  • 正文 年R本政府宣布,位于F島的核電站凌停,受9級(jí)特大地震影響粱年,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜罚拟,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,348評(píng)論 3 330
  • 文/蒙蒙 一台诗、第九天 我趴在偏房一處隱蔽的房頂上張望完箩。 院中可真熱鬧,春花似錦拉队、人聲如沸弊知。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,929評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)吉捶。三九已至,卻和暖如春皆尔,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背币励。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,048評(píng)論 1 270
  • 我被黑心中介騙來(lái)泰國(guó)打工慷蠕, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人食呻。 一個(gè)月前我還...
    沈念sama閱讀 48,203評(píng)論 3 370
  • 正文 我出身青樓流炕,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親仅胞。 傳聞我的和親對(duì)象是個(gè)殘疾皇子每辟,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,960評(píng)論 2 355

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