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;