記憶體洩漏及影響
記憶體洩漏是動態分配的記憶體塊,在程式的資料空間中任何位置都沒有指向它的指標。這類塊是孤立記憶體,由於沒有指向這些塊的指標,程式無法引用他們。
記憶體洩漏會導致App所佔用的虛擬記憶體增加,且通常產生記憶體碎片,影響App及整個系統的效能。
通常情況下,導致記憶體洩漏的原因是未釋放分配的記憶體,而又丟失指向分配塊的指標。
Leaks工具
Xcode的Instruments裡面有一個Leaks工具,可以幫助你定位發生記憶體洩漏的程式碼段,以便修復問題。
通過Xcode-Open Developer Tool-Instruments開啟Instruments皮膚,選擇Leaks工具,開啟後介面如下圖:
選擇Target,在右下角Display Setting皮膚的Call Tree,勾選Invert Call Tree和Hide System Libraries,方便接下來我們迅速查詢有記憶體問題的程式碼段。
點選Recorder Button開始監測,出現下圖紅色X號,表示此處有記憶體洩漏問題。
在時間軸上拖拽選擇X號前後區域,可以在左下皮膚看到所選時間段內呼叫的函式棧。
雙擊函式就可以開啟具體的程式碼段,比如最下面一個記憶體洩漏定位的程式碼段如下:
1 2 3 4 5 6 7 8 9 10 |
- (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]; } |
這個類非ARC的,很明顯olDic在alloc的時候Retain Count為1,setObject的時候Retain Count2變為2,導致記憶體洩漏。所以在setObject後面對olDic進行一次手動Release即可,如下:
1 2 3 4 5 6 7 8 9 10 11 |
- (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]; } |
後記
本文簡單介紹了使用Leaks定位和解決iOS應用的記憶體洩漏問題。雖然現在已經進入到ARC時代,但是很多大型專案由於歷史原因,使用ARC和MRC並存的記憶體管理方式,這種情況很容易產生記憶體洩漏。平時開發需要多留意編譯flag是否新增,對於MRC的程式碼要注意及時釋放記憶體,配合Leaks檢測定位記憶體問題。