內(nèi)存泄漏及影響
內(nèi)存泄漏是動(dòng)態(tài)分配的內(nèi)存塊,在程序的數(shù)據(jù)空間中任何位置都沒有指向它的指針屉栓。這類塊是孤立內(nèi)存舷蒲,由于沒有指向這些塊的指針,程序無法引用他們友多。
內(nèi)存泄漏會(huì)導(dǎo)致App所占用的虛擬內(nèi)存增加牲平,且通常產(chǎn)生內(nèi)存碎片,影響App及整個(gè)系統(tǒng)的性能域滥。
通常情況下纵柿,導(dǎo)致內(nèi)存泄漏的原因是未釋放分配的內(nèi)存,而又丟失指向分配塊的指針启绰。
Leaks工具
Xcode的Instruments里面有一個(gè)Leaks工具昂儒,可以幫助你定位發(fā)生內(nèi)存泄漏的代碼段,以便修復(fù)問題委可。
通過Xcode-Open Developer Tool-Instruments打開Instruments面板渊跋,選擇Leaks工具,打開后界面如下圖:
選擇?Target,在右下角Display Setting面板的Call Tree拾酝,勾選Invert Call Tree和Hide System Libraries燕少,方便接下來我們迅速查找有內(nèi)存問題的代碼段。
點(diǎn)擊Recorder Button開始監(jiān)測(cè)蒿囤,出現(xiàn)下圖紅色X號(hào)客们,表示此處有內(nèi)存泄漏問題。
在時(shí)間軸上拖拽選擇X號(hào)前后區(qū)域材诽,可以在左下面板看到所選時(shí)間段內(nèi)調(diào)用的函數(shù)棧底挫。
雙擊函數(shù)就可以打開具體的代碼段,比如最下面一個(gè)內(nèi)存泄漏定位的代碼段如下:
- (NSDictionary*)updateTimestampFrom:(NSMutableDictionary*)dict
{
int duration = [dict[OL][DURATION] intValue];
NSUInteger expiredAt = [[NSDate date] timeIntervalSince1970] + duration;
NSMutableDictionary *olDic = [[NSMutableDictionary alloc] initWithDictionary:dict[@"ol"]];
[olDic setObject:@(expiredAt) forKey:EXPIRED];
[dict setObject:olDic forKey:OL];
return [NSDictionary dictionaryWithDictionary:dict];
}
這個(gè)類非ARC的岳守,很明顯olDic在alloc的時(shí)候Retain Count為1凄敢,setObject的時(shí)候Retain Count2變?yōu)?,導(dǎo)致內(nèi)存泄漏湿痢。所以在setObject后面對(duì)olDic進(jìn)行一次手動(dòng)Release即可涝缝,如下:
- (NSDictionary*)updateTimestampFrom:(NSMutableDictionary*)dict
{
int duration = [dict[OL][DURATION] intValue];
NSUInteger expiredAt = [[NSDate date] timeIntervalSince1970] + duration;
NSMutableDictionary *olDic = [[NSMutableDictionary alloc] initWithDictionary:dict[@"ol"]];
[olDic setObject:@(expiredAt) forKey:EXPIRED];
[dict setObject:olDic forKey:OL];
[olDic release]
return [NSDictionary dictionaryWithDictionary:dict];
}
后記
本文簡(jiǎn)單介紹了使用Leaks定位和解決iOS應(yīng)用的內(nèi)存泄漏問題。雖然現(xiàn)在已經(jīng)進(jìn)入到ARC時(shí)代譬重,但是很多大型項(xiàng)目由于歷史原因拒逮,使用ARC和MRC并存的內(nèi)存管理方式,這種情況很容易產(chǎn)生內(nèi)存泄漏臀规。平時(shí)開發(fā)需要多留意編譯flag是否添加滩援,對(duì)于MRC的代碼要注意及時(shí)釋放內(nèi)存,配合Leaks檢測(cè)定位內(nèi)存問題塔嬉。