MLeaksFinder

MLeaksFinder 新特性

原文 http://wereadteam.github.io/2016/07/20/MLeaksFinder2/

主題 iOS開(kāi)發(fā)

MLeaksFinder 是 iOS 平臺(tái)的自動(dòng)內(nèi)存泄漏檢測(cè)工具沈善,引進(jìn) MLeaksFinder 后碘举,就可以在日常的開(kāi)發(fā)莫瞬,調(diào)試業(yè)務(wù)邏輯的過(guò)程中自動(dòng)地發(fā)現(xiàn)并警告內(nèi)存泄漏。開(kāi)發(fā)者無(wú)需打開(kāi) instrument 等工具,也無(wú)需為了找內(nèi)存泄漏而去跑額外的流程待讳。并且品擎,由于開(kāi)發(fā)者是在修改代碼之后一跑業(yè)務(wù)邏輯就能發(fā)現(xiàn)內(nèi)存泄漏的,這使得開(kāi)發(fā)者能很快地意識(shí)到是哪里的代碼寫(xiě)得問(wèn)題。這種及時(shí)的內(nèi)存泄漏的發(fā)現(xiàn)在很大的程度上降低了修復(fù)內(nèi)存泄漏的成本堡纬。

MLeaksFinder 0.1 開(kāi)源已經(jīng)有一段時(shí)間聂受,關(guān)于 MLeaksFinder 的基本原理,可以參考這篇文章烤镐。在 MLeaksFinder 開(kāi)源之后蛋济,收到的最多的反饋是:MLeaksFinder 幫忙發(fā)現(xiàn)了內(nèi)存泄漏,但是要去修復(fù)這些內(nèi)存泄漏炮叶,找到造成問(wèn)題的代碼很難碗旅,特別是對(duì)于歷史遺留的內(nèi)存泄漏。

現(xiàn)在镜悉,MLeaksFinder 0.2 來(lái)了祟辟。如果說(shuō) 0.1 版本旨在幫助開(kāi)發(fā)者發(fā)現(xiàn)內(nèi)存泄漏,那么 0.2 版本的新特性侣肄,正是旨在幫助開(kāi)發(fā)者更好地解決內(nèi)存泄漏旧困。MLeaksFinder 0.2 包括以下幾個(gè)新特性:

assert 改為 alert
追蹤對(duì)象的生命周期
查找循環(huán)引用鏈
下面,我們來(lái)逐一看一下這幾個(gè)特性稼锅。

assert 改為 alert

在 MLeaksFiner 0.1 版本吼具,當(dāng) MLeaksFinder 發(fā)現(xiàn)內(nèi)存泄漏時(shí),會(huì)直接中 assert 并打出內(nèi)存泄漏的信息矩距。Assert 能迫使開(kāi)發(fā)者及時(shí)地去修復(fù)內(nèi)存泄漏拗盒,并且,如果只是打日志锥债,內(nèi)存泄漏的日志很可能會(huì)被淹沒(méi)在眾多的日志中陡蝇。這種 assert 的方法在我們實(shí)際的項(xiàng)目取得了不錯(cuò)的效果。

然而哮肚,assert 確實(shí)也有不好的一面登夫。當(dāng)開(kāi)發(fā)者在調(diào)試業(yè)務(wù)邏輯的過(guò)程中,如果由于內(nèi)存泄漏中 assert 而使得整個(gè)程序掛掉了允趟,那么開(kāi)發(fā)者的思維會(huì)因此被打斷悼嫉,并不得不在修復(fù)完內(nèi)存泄漏之后,從頭開(kāi)始調(diào)試業(yè)務(wù)邏輯拼窥。有時(shí)候開(kāi)發(fā)者更希望的是連貫地調(diào)完整個(gè)業(yè)務(wù)邏輯之后戏蔑,再回過(guò)頭來(lái)修復(fù)內(nèi)存泄漏。

因此鲁纠,MLeaksFinder 0.2 把 assert 改成了 alert总棵。當(dāng)發(fā)現(xiàn)內(nèi)存泄漏之后,開(kāi)發(fā)者可以把 alert 框關(guān)掉改含,并繼續(xù)調(diào)試業(yè)務(wù)邏輯情龄。而且,把 assert 改成 alert 之后,也使得進(jìn)一步分析內(nèi)存成為可能骤视,為下面兩個(gè)新特性墊定基礎(chǔ)鞍爱。

追蹤對(duì)象的生命周期

當(dāng)發(fā)現(xiàn)可能的內(nèi)存泄漏對(duì)象并給出 alert 之后,MLeaksFinder 會(huì)進(jìn)一步地追蹤該對(duì)象的生命周期专酗,并在該對(duì)象釋放時(shí)給出 Object Deallocated 的 alert睹逃。

為什么認(rèn)為一個(gè)對(duì)象內(nèi)存泄漏之后,還要進(jìn)一步去追蹤該對(duì)象后續(xù)會(huì)不會(huì)釋放呢祷肯?MLeaksFinder 的基本原理是這樣的沉填,當(dāng)一個(gè) ViewController 被 pop 或 dismiss 之后,我們認(rèn)為該 ViewController佑笋,包括它上面的子 ViewController翼闹,以及它的 View,View 的 subView 等等蒋纬,都很快會(huì)被釋放猎荠,如果某個(gè) View 或者 ViewController 沒(méi)釋放,我們就認(rèn)為該對(duì)象泄漏了蜀备。然而关摇,這樣的判斷內(nèi)存泄漏的方法存在兩個(gè)可能的“誤判”:

  1. 單例或者被 cache 起來(lái)復(fù)用的 View 或 ViewController

對(duì)于這樣的 View 或 ViewController,在被 pop 或 dismiss 之后是不會(huì)被釋放的琼掠。然而,由于 View 相關(guān)的對(duì)象一般都占用了較多了內(nèi)存停撞,這樣的設(shè)計(jì)通常來(lái)說(shuō)不是好的設(shè)計(jì)瓷蛙。如果開(kāi)發(fā)者由于性能問(wèn)題等原因而不得不這樣設(shè)計(jì)的時(shí)候,開(kāi)發(fā)者可以在報(bào)泄漏的類(lèi)里重載 - (BOOL)willDealloc 方法戈毒,直接 return NO; 以消除內(nèi)存泄漏的警告艰猬,這個(gè)消除內(nèi)存泄漏警告的方法與 MLeaksFinder 0.1 版本一致。

  1. 釋放不及時(shí)的 View 或 ViewController

例如埋市,發(fā)起網(wǎng)絡(luò)請(qǐng)求的時(shí)候冠桃,在網(wǎng)絡(luò)請(qǐng)求回調(diào)的 block 里強(qiáng)引用 ViewController,以便在網(wǎng)絡(luò)請(qǐng)求回來(lái)的時(shí)候刷新界面道宅。在網(wǎng)絡(luò)請(qǐng)求比較慢的情況下食听,這種做法存在兩個(gè)問(wèn)題:

ViewController 被 pop 之后,由于被 block 強(qiáng)引用導(dǎo)致釋放不及時(shí)
ViewController 被 pop 之后污茵,如果網(wǎng)絡(luò)請(qǐng)求回來(lái)了樱报,不應(yīng)該繼續(xù)做刷新界面的事,浪費(fèi) CPU
所以泞当,對(duì)于這種情況迹蛤,我們應(yīng)該在 block 里弱引用 ViewController,而不是強(qiáng)引用。

下面我們來(lái)看如何利用對(duì)象的生命周期來(lái)分析內(nèi)存的真正使用情況盗飒,分三種情況:

  1. 單例或者被 cache 起來(lái)復(fù)用

如下面所示嚷量,在第一次 pop 的時(shí)候報(bào) Memory Leak,在之后的重復(fù) push 并 pop 同一個(gè) ViewController 過(guò)程中逆趣,即不報(bào) Object Deallocated蝶溶,也不報(bào) Memory Leak。這種情況下我們可以確定該對(duì)象被設(shè)計(jì)成單例或者 cache 起來(lái)了汗贫。

pop             push           pop           push          pop

----------> Leak ----------> | ----------> | ----------> | ---------->

  1. 釋放不及時(shí)

如下面所示身坐,在第一次 pop 的時(shí)候報(bào) Memory Leak,在之后的重復(fù) push 并 pop 同一個(gè) ViewController 過(guò)程中落包,對(duì)于同一個(gè)類(lèi)不斷地報(bào) Object Deallocated 和 Memory Leak部蛇。這種情況屬于釋放不及時(shí)的情況。

pop             push                 pop             push                 pop

----------> Leak ----------> Dealloc ----------> Leak ----------> Dealloc ----------> Leak

  1. 真正的內(nèi)存泄漏

如下面所示咐蝇,在第一次 pop 的時(shí)候報(bào) Memory Leak涯鲁,在之后的重復(fù) push 并 pop 同一個(gè) ViewController 過(guò)程中,不報(bào) Object Deallocated有序,但每次 pop 之后又報(bào) Memory Leak抹腿。這種情況下每回進(jìn)入并退出一個(gè)頁(yè)面后,就報(bào)有新的內(nèi)存泄漏旭寿,同時(shí)被報(bào)泄漏的對(duì)象又從來(lái)沒(méi)有釋放過(guò)警绩,可以確定是真正的內(nèi)存泄漏。

pop             push           pop             push           pop

----------> Leak ----------> | ----------> Leak ----------> | ----------> Leak
查找循環(huán)引用鏈

Facebook 在前陣子開(kāi)源了一個(gè)循環(huán)引用檢測(cè)工具 FBRetainCycleDetector 盅称。當(dāng)傳入內(nèi)存中的任意一個(gè) OC 對(duì)象肩祥,F(xiàn)BRetainCycleDetector 會(huì)遞歸遍歷該對(duì)象的所有強(qiáng)引用的對(duì)象,以檢測(cè)以該對(duì)象為根結(jié)點(diǎn)的強(qiáng)引用樹(shù)有沒(méi)有循環(huán)引用缩膝。

我們知道混狠,很多循環(huán)引用是 block 的使用不當(dāng)造成的。而 FBRetainCycleDetector 最大的技術(shù)亮點(diǎn)疾层,正在于如何找出一個(gè) block 的所有強(qiáng)引用對(duì)象将饺。對(duì)于這個(gè)感興趣的,可以看 facebook 的這篇 文章 痛黎。

然而予弧,F(xiàn)BRetainCycleDetector 的使用存在兩個(gè)問(wèn)題:

需要找到候選的檢測(cè)對(duì)象
檢測(cè)循環(huán)引用比較耗時(shí)
正是由于這兩個(gè)問(wèn)題,F(xiàn)BRetainCycleDetector 通常是結(jié)合其它工具一起使用湖饱,通過(guò)其它工具先找出候選的檢測(cè)對(duì)象桌肴,然后進(jìn)行有選擇的檢測(cè)。當(dāng) MLeaksFinder 與 FBRetainCycleDetector 結(jié)合使用時(shí)琉历,正好能達(dá)到很好的效果坠七。我們先通過(guò) MLeaksFinder 找到內(nèi)存泄漏的對(duì)象水醋,然后再過(guò) FBRetainCycleDetector 檢測(cè)該對(duì)象有沒(méi)有循環(huán)引用即可。

循環(huán)引用的輸出信息如下:

(
"-> MyTableViewCell ",
"-> _callback -> NSMallocBlock "
)
上面的信息表示彪置, MyTableViewCell 有一個(gè)強(qiáng)引用的成員變量 _callback 拄踪,該變量的類(lèi)型是 NSMallocBlock ,在 _callback 里拳魁,又強(qiáng)引用了 MyTableViewCell 造成循環(huán)引用惶桐。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市潘懊,隨后出現(xiàn)的幾起案子姚糊,更是在濱河造成了極大的恐慌,老刑警劉巖授舟,帶你破解...
    沈念sama閱讀 211,639評(píng)論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件救恨,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡释树,警方通過(guò)查閱死者的電腦和手機(jī)肠槽,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,277評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)奢啥,“玉大人秸仙,你說(shuō)我怎么就攤上這事∽ぃ” “怎么了寂纪?”我有些...
    開(kāi)封第一講書(shū)人閱讀 157,221評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)赌结。 經(jīng)常有香客問(wèn)我捞蛋,道長(zhǎng),這世上最難降的妖魔是什么姑曙? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 56,474評(píng)論 1 283
  • 正文 為了忘掉前任襟交,我火速辦了婚禮迈倍,結(jié)果婚禮上伤靠,老公的妹妹穿的比我還像新娘。我一直安慰自己啼染,他們只是感情好宴合,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,570評(píng)論 6 386
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著迹鹅,像睡著了一般卦洽。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上斜棚,一...
    開(kāi)封第一講書(shū)人閱讀 49,816評(píng)論 1 290
  • 那天阀蒂,我揣著相機(jī)與錄音该窗,去河邊找鬼。 笑死蚤霞,一個(gè)胖子當(dāng)著我的面吹牛酗失,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播昧绣,決...
    沈念sama閱讀 38,957評(píng)論 3 408
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼规肴,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了夜畴?” 一聲冷哼從身側(cè)響起拖刃,我...
    開(kāi)封第一講書(shū)人閱讀 37,718評(píng)論 0 266
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎贪绘,沒(méi)想到半個(gè)月后兑牡,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,176評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡兔簇,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,511評(píng)論 2 327
  • 正文 我和宋清朗相戀三年发绢,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片垄琐。...
    茶點(diǎn)故事閱讀 38,646評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡边酒,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出狸窘,到底是詐尸還是另有隱情墩朦,我是刑警寧澤,帶...
    沈念sama閱讀 34,322評(píng)論 4 330
  • 正文 年R本政府宣布翻擒,位于F島的核電站氓涣,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏陋气。R本人自食惡果不足惜劳吠,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,934評(píng)論 3 313
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望巩趁。 院中可真熱鬧痒玩,春花似錦、人聲如沸议慰。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,755評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)别凹。三九已至草讶,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間炉菲,已是汗流浹背堕战。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,987評(píng)論 1 266
  • 我被黑心中介騙來(lái)泰國(guó)打工坤溃, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人嘱丢。 一個(gè)月前我還...
    沈念sama閱讀 46,358評(píng)論 2 360
  • 正文 我出身青樓浇雹,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親屿讽。 傳聞我的和親對(duì)象是個(gè)殘疾皇子昭灵,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,514評(píng)論 2 348

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