項目(ARC)開發過程中,難免遇到記憶體洩漏和崩潰,特在這整理一下。(如果本文中有講述不對或者不準确的地方歡迎大家提出來)
一、記憶體洩漏
1、EXC_BAD_ACCESS / KERN_INVALID_ADDRESS

公司的項目接入了三方崩潰報告,最近出現了
EXC_BAD_ACCESS / KERN_INVALID_ADDRESS
這樣的錯誤,崩潰報告堆棧資訊一大堆,看的頭暈。
How to fix it?
這個奔潰常見于block的循環引用所造成的記憶體洩漏
//一個簡單的例子
SecondViewController *secondVC = [[SecondViewController alloc] init];
__weak __typeof(&*self)weakSelf = self;
[secondVC setChangeLabel:^(NSString *text) {
weakSelf.text = text;
}];
我們定義一個
wself
變量并加上
__weak
修飾符,在
Block
中,所有需要
self
的地方都用
wself
來替代。這樣就不會增加引用計數,是以block持有
self
對象也就不會造成循環引用,進而造成記憶體洩漏。
2、Value stored to ‘dic’ during its initialization is never read
這個是在測試項目記憶體洩漏的時候遇到的 (Product->Analyze)
//記憶體洩漏代碼
NSDictory *dic = [[NSDictory alloc] init];
dic = {@"0",@"1",@"2"};
這麼寫真是太逗了,像什麼
NSArray
,
NSString
等等都有可能遇到這種低級錯誤
//這麼寫就好了啊
NSDictory *dic = {@"0",@"1",@"2"};
3、Potential leak of an object stored into ‘string’
這個同樣是在測試項目記憶體洩漏的時候遇到的 (Product->Analyze)
//why crash
+ (NSString *)uuidString {
CFUUIDRef theUniqueString = CFUUIDCreate(NULL);
CFStringRef string = CFUUIDCreateString(NULL, theUniqueString);
CFRelease(theUniqueString);
return(__bridgeNSString *)string;
}
這個是沒有release對象造成的。
//fix it
+ (NSString*)uuidString {
CFUUIDReftheUniqueString =CFUUIDCreate(NULL);
CFStringRefstring =CFUUIDCreateString(NULL, theUniqueString);
NSString*tmpString = (__bridgeNSString*)string;
CFRelease(theUniqueString);
CFRelease(string);
returntmpString;
}
像什麼
subImageRef
,
CGGradientRef
,
CTFrameRef
等等都有可能遇到這種錯誤。
二、崩潰
1、
我們可以打開
Product->Scheme->Edit Scheme->Run->Diagnostics
将
Enable Zombie Objects
勾選上,然後打全局斷點進行測試,如果複現了這個崩潰,控制台會輸出錯誤資訊,例如
-[XXXXX getObjectAt:]: message sent to deallocated instance 0x11562a300
。
2、
我們可以在添加到數組之前做一下判斷
if (nameStr == nil || [nameStr isKindOfClass:[NSNull class]]) {
[nameArr addObject:@"匿名使用者"];
}else {
[nameArr addObject:nameStr];
}
3、
我們可以自己寫一個方法代替系統的擷取數組中對象的方法
objectAtIndex:
- (id)objectAtIndexCheck:(NSUInteger)index{
//越界
if (index >= [self count]) {
return nil;
}
id value = [self objectAtIndex:index];
//對象為空
if (value == [NSNull null]) {
return nil;
}
return value;
}
4、
1、使用标準的初始化方法:
NSDictionary *dictionary =[[NSDictionaryalloc] initWithObjectsAndKeys:value1,@”key1”,value2,@”key2”, value3 ,@”value3”,nil];
2、使用ios6.0以後新支援的初始化方法:
NSDictionary *dictionary =@{@”key1” : value1,@”key2” : value2,@”key3” : value3};
現在我們對value1 value2 value3進行指派,并把value2設為nil指針:
NSString *value1 =@”value1”;NSString *value2 =nil;NSString *value3 =@”value3”;
這時如果使用第二種初始化方法,運作程式會發現崩潰,日志如下:
***
Terminating app due to uncaught exception 'NSInvalidArgumentException',
reason: '***
-[__NSPlaceholderDictionary initWithObjects:forKeys:count:]: attempt to insert nil object from objects[]'
也就是說使用這種初始化方法的時候必須保證key跟value都不為nil,是以我們需要在初始化之前對其進行判斷,如果為nil就不加入字典。但是如果有需求讓value必須為空的時候,可以将value指派為[NSNull null]
這樣就可以成功插入字典
5、
[cell setColumnTitle:[homeData objectAtIndex:row]];
這裡其實是要傳NSString類型,而其實傳回的是NSArray類型,這個錯誤不會立即出發,而是過一段時間再出發,是以不好定位。
先寫這麼多,大家遇到的問題歡迎補充。
O(∩_∩)O步進共同