更新
升級(jí)到 Xcode8之后, 這個(gè)庫好像沒有用了, 具體原因也不詳細(xì)追究了, 因?yàn)?Xcode 自帶了強(qiáng)大的 Debug Memory Graph, 直接以關(guān)系圖的形式來告訴你各個(gè)對(duì)象的持有關(guān)系, 以及出現(xiàn)了泄露時(shí)會(huì)有紫色的小感嘆號(hào)出現(xiàn), 不出現(xiàn)也不意味著沒有喲, 所以還需要用這個(gè)工具時(shí)不時(shí)看看現(xiàn)有的存活對(duì)象中有沒有期望之外的.
下面是一些關(guān)鍵步驟的截圖:
如果在警告列表中沒有看到任何東西, 先切換到 BuildTime 那里把右下角的警告篩選給關(guān)了就會(huì)出現(xiàn)了, 個(gè)人認(rèn)為這是 Xcode 的一個(gè) bug...
選中某個(gè)泄露對(duì)象后會(huì)出現(xiàn)持有和它有關(guān)系的對(duì)象關(guān)系圖, 如下:
這個(gè)例子說我們的 ViewController 被 block 持有了, 點(diǎn)擊紅圈里面的展開可以看到更多的信息, 具體過程就不詳細(xì)講了, 因?yàn)檫@里給到的信息已經(jīng)足夠詳細(xì), 再需要一些耐心就可以找出具體的原因了.
!注意: 不要開著 NSZombie 來檢測(cè), 不然你會(huì)發(fā)現(xiàn)一大票的泄露.
新工具簡(jiǎn)介就到這邊了, 下面的老的MLeaksFinder的內(nèi)容, 已經(jīng)過時(shí), 不讀也罷...
前言
一般來說, iOS的內(nèi)存泄露檢測(cè)大多是通過Instruments里面的Leaks. Leaks里面可以看到某各類有多少個(gè)實(shí)例, 還會(huì)指出一些循環(huán)引用的圖示和泄露點(diǎn). 雖然看起來很美好, 但是每次實(shí)際使用的時(shí)候, 多多少少會(huì)出現(xiàn)一些問題, 最讓人難以忍受的就是明明泄露了但是沒有報(bào)警.
為了解決這個(gè)問題, 在這里介紹一個(gè)MLeaksFinder的開源庫, 這個(gè)庫是代碼級(jí)別的檢測(cè)view和viewController是否出現(xiàn)內(nèi)存泄露的情況. 它的優(yōu)勢(shì)是只要引入后不侵入現(xiàn)有代碼, 正常跑一遍APP, 如果出現(xiàn)泄露, 將會(huì)觸發(fā)斷言打印相關(guān)日志提醒我們出現(xiàn)了泄露. 缺點(diǎn)也比較明顯了, 就是只能檢測(cè)view和viewController級(jí)別的泄露. 不過一般來說也足夠用了, 畢竟這是大頭.
github地址:https://github.com/Zepo/MLeaksFinde
原理
MLeaksFinder的原理還是很簡(jiǎn)單的, 它swizzle了NavigationController的Push和Pop相關(guān)方法來管理viewController和view的生命周期, 在你Pop掉viewController的時(shí)候, 會(huì)執(zhí)行這么一段代碼
__weak id weakSelf = self;
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
[weakSelf assertNotDealloc];
});
3秒后執(zhí)行 [weakSelf assertNotDealloc]; 如果這個(gè)時(shí)候view和viewController已經(jīng)釋放了, 那么weakSelf應(yīng)該為nil, 所以將不會(huì)觸發(fā)斷言, 否則將會(huì)打印日志, 觸發(fā)斷言.
實(shí)際操作
為了驗(yàn)證是否真正出現(xiàn)泄漏的情況, 可以在出現(xiàn)斷言的時(shí)候, 進(jìn)入Instruments的Leaks來看查看類實(shí)例個(gè)數(shù), 反復(fù)進(jìn)入目標(biāo)頁面后可以查看目標(biāo)類的實(shí)例情況,例如:
Persistent是當(dāng)前的實(shí)例個(gè)數(shù), 如果發(fā)現(xiàn)Pop之后沒有減少, 就肯定是泄漏了. 這里也吐槽一下Instrument, 這種情況是檢測(cè)不出來的.
發(fā)現(xiàn)泄漏點(diǎn)是第一步, 后面還要看怎么泄漏, 方法還是有很多的, 可以自己查相關(guān)頁面的代碼, 我的操作步驟一般是:
2). 進(jìn)入到實(shí)例頁面之后, 再選中實(shí)例再點(diǎn)擊箭頭會(huì)出現(xiàn)retain和release的時(shí)序列表. 這個(gè)時(shí)候很卡的話建議暫停運(yùn)行APP
3). 在這個(gè)時(shí)序表中查看有沒有不該retain但是retain了的函數(shù), 一般只需要看那些單獨(dú)+1 -1的行, 說明這里的retain和release是沒有平衡起來的, 除非是系統(tǒng)代碼或者有意為之, 否則都會(huì)有一些問題.
4). 發(fā)現(xiàn)可疑點(diǎn)之后, 雙擊進(jìn)入相關(guān)代碼, 查看泄露情況, 一般是選擇泄露比重最大的那一行代碼, 然后進(jìn)行深入分析.
5). 如果你也曾經(jīng)出現(xiàn)死活都找不到泄露的位置, 那么時(shí)候祭出大殺器--注釋代碼了.
另外, 對(duì)于一些view的泄露, 還是要善用一下Xcode自帶的功能, 一般我的操作會(huì)是跳到UIImageView或者UILabel的泄漏點(diǎn)選中self, 然后在變量區(qū)下面點(diǎn)擊那個(gè)眼睛, 如下圖:
看到里面的內(nèi)容就能大致猜出出現(xiàn)泄漏的地方了, 一般而言, view單獨(dú)泄漏的情況還是比較少的, 雖然也出現(xiàn)過, 但是總體而言都是viewController的泄漏連帶了view的泄漏.
結(jié)語
這個(gè)簡(jiǎn)單的庫幫助我找到了很多Instruments沒有報(bào)警的泄漏點(diǎn), 個(gè)人覺得很好用, 而且引入進(jìn)來就算忘記移出也沒關(guān)系, 已經(jīng)用DEBUG宏包裹起來了, 不會(huì)影響到發(fā)布.
另外, 有沒有同學(xué)遇到過前端頁面用了-webkit-overflow-scrolling:touch導(dǎo)致出現(xiàn)UIWebOverflowScrollView泄露的啊? 求指導(dǎo)解決.