天天看點

iOS開發 一些常見的記憶體洩露和崩潰一、記憶體洩漏二、崩潰

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

一、記憶體洩漏

1、EXC_BAD_ACCESS / KERN_INVALID_ADDRESS

iOS開發 一些常見的記憶體洩露和崩潰一、記憶體洩漏二、崩潰

公司的項目接入了三方崩潰報告,最近出現了

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

iOS開發 一些常見的記憶體洩露和崩潰一、記憶體洩漏二、崩潰

這個是在測試項目記憶體洩漏的時候遇到的 (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’

iOS開發 一些常見的記憶體洩露和崩潰一、記憶體洩漏二、崩潰

這個同樣是在測試項目記憶體洩漏的時候遇到的 (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、

iOS開發 一些常見的記憶體洩露和崩潰一、記憶體洩漏二、崩潰

我們可以打開

Product->Scheme->Edit Scheme->Run->Diagnostics

Enable Zombie Objects

勾選上,然後打全局斷點進行測試,如果複現了這個崩潰,控制台會輸出錯誤資訊,例如

-[XXXXX getObjectAt:]: message sent to deallocated instance 0x11562a300

2、

iOS開發 一些常見的記憶體洩露和崩潰一、記憶體洩漏二、崩潰

我們可以在添加到數組之前做一下判斷

if (nameStr == nil || [nameStr isKindOfClass:[NSNull class]])  {
    [nameArr addObject:@"匿名使用者"];
}else {
    [nameArr addObject:nameStr];
 }
           

3、

iOS開發 一些常見的記憶體洩露和崩潰一、記憶體洩漏二、崩潰
iOS開發 一些常見的記憶體洩露和崩潰一、記憶體洩漏二、崩潰

我們可以自己寫一個方法代替系統的擷取數組中對象的方法

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、

iOS開發 一些常見的記憶體洩露和崩潰一、記憶體洩漏二、崩潰

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、

iOS開發 一些常見的記憶體洩露和崩潰一、記憶體洩漏二、崩潰

[cell setColumnTitle:[homeData objectAtIndex:row]];

這裡其實是要傳NSString類型,而其實傳回的是NSArray類型,這個錯誤不會立即出發,而是過一段時間再出發,是以不好定位。

先寫這麼多,大家遇到的問題歡迎補充。

O(∩_∩)O