1. 程式人生 > >iOS記憶體優化

iOS記憶體優化

1、執行MemoryProblems後,執行崩潰出現EXC_BAD_ACCESS,啟動NSZombieEnabled,選中Edit Scheme並點選,Run -> Diagnostics -> Enable Zombie Objects(懸掛指標的檢測),設定完之後,再次執行和點選頁面,雖然會再次crash,但這次控制檯列印了有用資訊,點選Continue program execution按鈕繼續執行,對比找到相同地址並修改(啟動MallocStackLogging

常見原因:某變數被assign修飾,對變數值後,它的物件就馬上釋放,而變數也不是strong而是weak,此時仍然使用就會導致程式crash

2、手動靜態分析:應用Product—>Analyze或捷鍵shift + command + b進行記憶體洩漏的初步檢測

    自動靜態分析:在Build Settings啟用Analyze During 'Build',每次編譯時都會自動靜態分析

3、可以在xcode的build setting中開啟implicit retain of ‘self’ within blocks,xcode編譯器會給出警告,逐個排查警告

4、應用Leak Instrument進行記憶體洩露查詢:點選Xcode的選單欄的 Product -> Profile 啟動Instruments,出現Instruments的工具集,選中Leaks子工具點選,點選紅色圓點按鈕啟動Leaks工具,在Leaks工具啟動同時,模擬器或真機也跟著啟動,啟動Leaks工具後,它會在程式執行時記錄記憶體分配資訊和檢查是否發生記憶體洩露

首先點選Leak Checks時間條那個紅色叉,點選紅色叉後,下面顯示Leaks By Backtrace,雙擊某行記憶體洩露呼叫棧,會直接跳到記憶體洩露程式碼位置

Leak Instrument有Cycles & Roots介面:Persistent Bytes和#Persistent。#Persistent是object的數量,也就是allocation的次數,而Persistent Bytes是具體的記憶體大小。#Persistent是我們需要關注的,記憶體有沒有洩露也是看這個值是不是隻增不減。

Allocations:啟動Allocations,勾選列表最上邊的,右邊設定勾選:Discard unrecorded data upon stop、Identify virtual C++ objects、* isContain…Record 

列表勾選VM

Generation Analysis

這個功能是非常有用的,一般是這樣用的:進入一個頁面前mark一下,在退出這個頁面的時候再mark一下可以比較哪些內容增加了,就可以具體分析哪些記憶體沒有被釋放

Call Tree:需要我們把列表展示型別切換成Call Trees,能夠非常清晰的看到呼叫樹

Separate by Category:按照類別隔開,我們鉤上看看效果

Separate by Thread:按照執行緒劃分,我個人不是很喜歡這種劃分,因為我不是很關心執行緒

Invert Call Tree:反轉呼叫,我們給一張對比圖就不需要解釋了

Hide System Libraries:這個似乎是必鉤的,因為我們目前只關心自己的方法,不關心繫統的

Flatten Recursion:扁平化遞迴

Data Mining:資料探勘,這是一個很具有噱頭的功能

點選Symbol、Library會自動把你選中的行的符號、庫加到小框中

符號和庫有兩個選項,就是是否過濾改行;點選Restore會去掉小框中的選中行

5、通過檢視dealloc是否呼叫檢視某個class是否洩漏問題

- (void)dealloc

{

NSLog(@"release XXXXViewController");

}

方法:__weakXXXXViewController *weakSelf = self;在Block裡用weakSelf

常見問題:

1、UITextField在iOS 11記憶體洩漏問題:UITextField沒釋放原因使用secureTextEntry屬性,解決方案

- (BOOL)textFieldShouldBeginEditing:(UITextField *)textField {

    if (textField == self.passWordTextField) {

        textField.secureTextEntry = YES;

    }else {

        textField.secureTextEntry = NO;

    }

returnYES;

}

2、使用CGMutablePathRef path = CGPathCreateMutable();時出現Potential leak of an object stored into 'path’解決方案

CGPathRelease(path);

creat,copy作為關鍵字的函式都是需要釋放記憶體的,注意配對使用。比如:CGColorCreate<-->CGColorRelease

3、The 'viewWillDisappear:' instance method in UIViewController subclass 

XXX is missing a [super viewWillDisappear:] callm,解決方案

- (void)viewWillAppear:(BOOL)animated {

    [super viewWillAppear:animated];

}

4、呼叫

+ (NSTimer *)scheduledTimerWithTimeInterval:(NSTimeInterval)ti target:(id)aTarget selector:(SEL)aSelector userInfo:(nullable id)userInfo repeats:(BOOL)yesOrNo;

方法之後在不需要NSTimer時及時呼叫[self.timerinvalidate];千萬不要在dealloc方法中呼叫,因為NSTimer強引用self,所以不會執行dealloc方法。

5、物件之間的迴圈引用:例子:兩個ViewController都需要使用對方,這個時候可以用@class ; 

說明:在 .h 中引入某個類, @class 指的是 當前檔案 只是引入類名, 並沒有使用類裡面的東西. 想要在 .m 裡面使用 類的內容的話, 還是要 #import <>, 這種情況跟 上面的物件之間的防止迴圈引 有點不一樣

6、如果是C申請的記憶體,注意new delete, malloc free的配對處理。

7、圖片相關:

快取:imageNamed:

只需傳入檔名.副檔名即可。

可以載入bundle中任意位置的圖片,包括main bundle中其他bundle的。

imageNamed方法建立物件的步驟如下:

7.1根據圖片檔名在快取池中查詢圖片資料,如存在,則建立物件並返回;

7.2如果不存在,則從bundle中載入圖片資料,建立物件並返回;

7.3如果相應的圖片資料不存在,返回nil。

不快取:imageWithContentsOfFile:

必須傳入圖片檔案的全名(全路徑+檔名)

無法載入Images.xcassets中的圖片。

對於大的圖片且偶爾需要顯示的應放到工程目錄下,不要放到Assets.xcassets中;並使用imageWithContentsOfFile載入不讓系統快取

background.image = [UIImage imageWithContentsOfFile:[[[NSBundle mainBundle] bundlePath] stringByAppendingString:@"/*.png"]];

對於經常需要展示的小圖片放到Assets.xcassets中讓系統快取,使用imageNamed載入

background.image = [UIImage imageNamed:@"*.png"];

不常用大圖:將imageView.image = [UIImage imageNamed:nameArr[index]];

改為imageView.image = [UIImage imageWithContentsOfFile:[[NSBundle mainBundle] pathForResource:nameArr[index] ofType:@"png"]];

8、出現VM:CG raster data,SDWebImage的問題

需要在Appdelegate中設定一下

[[SDImageCache sharedImageCache] setShouldDecompressImages:NO];

[[SDWebImageDownloader sharedDownloader] setShouldDecompressImages:NO];

[[SDImageCache sharedImageCache] setShouldCacheImagesInMemory:NO];

9、VM:CoreAnimation

Found out that animation caused by the inner pages.

Inside the pageViewController(viewController that added to the scrollView as a page) on viewWillDisappear:(BOOL)animated method I added this

for (CALayer* layer in [self.view.layer sublayers]) {

        [layer removeAllAnimations];

}

it resolved the problem.

10、@property (readwrite, nonatomic, copy) NSMutableURLRequest *request;出現Property of mutable type 'NSMutableURLRequest' has 'copy' attribute; an immutable object will be stored instead,解決方案

@property (readwrite, nonatomic, strong) NSMutableURLRequest *request;