內(nèi)存泄露問(wèn)題分析

一般引起內(nèi)存泄露的可能

1、delegate使用strong引用,如果父VC持有子VC,并設(shè)置VC的delegate為self(也就是父VC),這樣的結(jié)果就是子VC也間接持有了父VC,造成了循環(huán)引用,在Pop子VC的時(shí)候不會(huì)調(diào)用dealloc

2、timer是否沒(méi)有invalidate,scheduledTimerWithTimeInterval:target:selector:userInfo:

這里的target一般是self,這個(gè)時(shí)候就需要注意了,在退出時(shí)候,如果timer還在執(zhí)行的話,有timer會(huì)持有self,所以也不會(huì)調(diào)dealloc

確保timer有invalidate,或使用弱引用weakSelf來(lái)替代self

3、最常見(jiàn)的其實(shí)是block引起的循環(huán)引用問(wèn)題

block的引用分以下三種情況

1)不作為成員變量

[self oneBlockSucess:^{

????????[self doSomething];

?}];

2)成員變量,直接引用

self.secondBlock = ^{?

????????[self doSomething];?

};

3)成員變量,間接引用

typedef void(^BtnPressedBlock)(UIButton*btn);

@interface XXSubmitBottomView:UIView

@property(nonatomic,copy)BtnPressedBlock block;

-(void)submittBtnPressed:(BtnPressedBlock)block;

@end

@implementation XXConfirmOrderController

if(!_bottomView) {

?????????_bottomView = [[XXSubmitBottomView alloc] initWithFrame:CGRectMake(0,self.view.height -50, Width,50)];?

?????????_bottomView.currentVc =self;

#warning self.bottomView.block self間接持有了BtnPressedBlock 必須使用weak!

WEAKSELF//ps: weakSelf的宏定義#define WEAKSELF typeof(self) __weak weakSelf = self;

????????[_bottomView submittBtnPressed:^(UIButton*btn) {

????}

}

把self通過(guò)參數(shù)回傳給block,這樣就不會(huì)產(chǎn)生循環(huán)引用了。

block回傳的self可以聲明成id類型,這樣使用的時(shí)候可以在入?yún)⒙暶骶唧wself類型,避免顯式類型轉(zhuǎn)換,方便開發(fā)。

注意:block 內(nèi)部有延遲操作的時(shí)候,使用外部聲明的強(qiáng)引用

這時(shí)候你會(huì)發(fā)現(xiàn),在打印 block 內(nèi)容的之前,person 對(duì)象已經(jīng)被釋放了,自然,name 屬性的值,也是空的了。

另外也不只是after,asyn等都是這種情況。

此時(shí)需要使用

__strong ClassName *sself = wself;



總結(jié):存在使用了類的成員變量而導(dǎo)致循環(huán)引用的情況,需要使用__weak來(lái)弱引用。

????????????要判斷A是否引用B

4、CoreFoundation對(duì)象(C對(duì)象,或單獨(dú)與C混編) : 只要函數(shù)中包含了create\new\copy\retain等關(guān)鍵字, 那么這些方法產(chǎn)生的對(duì)象, 就必須在不再使用的時(shí)候調(diào)用1次CFRelease或者其他release函數(shù)


以上是內(nèi)存泄露的可能原因,但是如何檢測(cè)內(nèi)存泄露,并快速定位呢?

Instrument其實(shí)有很多不便

Leaks

先看看 Leaks,從蘋果的開發(fā)者文檔里可以看到,一個(gè) app 的內(nèi)存分三類:

Leaked memory: Memory unreferenced by your application that cannot be used again or freed (also detectable by using the Leaks instrument).

Abandoned memory: Memory still referenced by your application that has no useful purpose.

Cached memory: Memory still referenced by your application that might be used again for better performance.

1、 Leaked memory 和 Abandoned memory 都屬于應(yīng)該釋放而沒(méi)釋放的內(nèi)存,都是【內(nèi)存泄露】。

2、而 Leaks 工具只負(fù)責(zé)檢測(cè) Leaked memory,而不管 Abandoned memory。在 MRC 時(shí)代 Leaked memory 很常見(jiàn),因?yàn)楹苋菀淄苏{(diào)用 release,但在 ARC 時(shí)代更常見(jiàn)的內(nèi)存泄露是循環(huán)引用導(dǎo)致的 Abandoned memory,Leaks 工具查不出這類內(nèi)存泄露,應(yīng)用有限。

MLeaksFinder 框架

MLeaksFinder提供了內(nèi)存泄露檢測(cè)更好的解決方案。

1、只需要引入 MLeaksFinder,就可以自動(dòng)在 App 運(yùn)行過(guò)程檢測(cè)到內(nèi)存泄露的對(duì)象并立即提醒,

2、無(wú)需打開額外的工具。

3、也無(wú)需為了檢測(cè)內(nèi)存泄露而一個(gè)個(gè)場(chǎng)景去重復(fù)地操作。

總結(jié):MLeaksFinder 目前能自動(dòng)檢測(cè) UIViewController 和 UIView 對(duì)象的內(nèi)存泄露,而且也可以擴(kuò)展以檢測(cè)其它類型的對(duì)象。

MLeaksFinder 的使用很簡(jiǎn)單

參照https://github.com/Zepo/MLeaksFinder,基本上就是把 MLeaksFinder 目錄下的文件添加到你的項(xiàng)目中,就可以在運(yùn)行時(shí)(debug 模式下)幫助你檢測(cè)項(xiàng)目里的內(nèi)存泄露了,無(wú)需修改任何業(yè)務(wù)邏輯代碼,而且只在 debug 下開啟,完全不影響你的 release 包。

當(dāng)發(fā)生內(nèi)存泄露時(shí),MLeaksFinder 會(huì)中斷言,并準(zhǔn)確的告訴你哪個(gè)對(duì)象泄露了。這里設(shè)計(jì)為中斷言而不是打日志讓程序繼續(xù)跑,是因?yàn)楹芏嗳瞬粫?huì)去看日志,斷言則能強(qiáng)制開發(fā)者注意到并去修改,而不是犯拖延癥。

中斷言時(shí),控制臺(tái)會(huì)有如下提示,View-ViewController stack 從上往下看,該 stack 告訴你,MyTableViewController 的 UITableView 的 subview UITableViewWrapperView 的 subview MyTableViewCell 沒(méi)被釋放。而且,這里我們可以肯定的是 MyTableViewController,UITableView,UITableViewWrapperView 這三個(gè)已經(jīng)成功釋放了。

從 MLeaksFinder 的使用方法可以看出,MLeaksFinder 具備以下優(yōu)點(diǎn):

1、使用簡(jiǎn)單,不侵入業(yè)務(wù)邏輯代碼。

2、不用打開 Instrument不需要額外的操作,你只需開發(fā)你的業(yè)務(wù)邏輯,在你運(yùn)行調(diào)試時(shí)就能幫你檢測(cè)內(nèi)存泄露發(fā)現(xiàn)及時(shí),更改完代碼后一運(yùn)行即能發(fā)現(xiàn)(這點(diǎn)很重要,你馬上就能意識(shí)到哪里寫錯(cuò)了)精準(zhǔn),能準(zhǔn)確地告訴你哪個(gè)對(duì)象沒(méi)被釋放

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容