一、基本概念
- 內(nèi)存泄漏(memory leak):是指申請(qǐng)的內(nèi)存空間使用完畢之后未回收。
一次內(nèi)存泄露危害可以忽略,但若一直泄漏,無(wú)論有多少內(nèi)存,遲早都會(huì)被占用光,最終導(dǎo)致程序crash。(因此,開發(fā)中我們要盡量避免內(nèi)存泄漏的出現(xiàn))- 內(nèi)存溢出(out of memory):是指程序在申請(qǐng)內(nèi)存時(shí),沒有足夠的內(nèi)存空間供其使用。
通俗理解就是內(nèi)存不夠用了,通常在運(yùn)行大型應(yīng)用或游戲時(shí),應(yīng)用或游戲所需要的內(nèi)存遠(yuǎn)遠(yuǎn)超出了你主機(jī)內(nèi)安裝的內(nèi)存所承受大小,就叫內(nèi)存溢出。最終導(dǎo)致機(jī)器重啟或者程序crash。
二、常見內(nèi)存泄露
1、NSTimer循環(huán)引用
[NSTimer scheduledTimerWithTimeInterval:1.0
target:self
selector:@selector(updateTime:)
userInfo:nil
repeats:YES];
- 理由: 這時(shí) target: self,增加了ViewController的retain count,
即self強(qiáng)引用timer,timer強(qiáng)引用self,造成循環(huán)引用。
2、ViewController中的代理delegate
- 理由:如果代理用strong修飾,ViewController(self)會(huì)強(qiáng)引用View,View強(qiáng)引用delegate,delegate內(nèi)部強(qiáng)引用ViewController(self)。造成內(nèi)存泄漏。
- 解決方案:代理盡量使用weak修飾。
@class QiAnimationButton;
@protocol QiAnimationButtonDelegate <NSObject>
- (void)animationButton:(QiAnimationButton *)button willStartAnimationWithCircleView:(QiCircleAnimationView *)circleView;
@end
@interface QiAnimationButton : UIButton
@property (nonatomic, weak) id <QiAnimationButtonDelegate> delegate;
3、Block
- 理由:如果block被當(dāng)前ViewController(self)持有,這時(shí),如果block內(nèi)部再持有ViewController(self),就會(huì)造成循環(huán)引用。
- 解決方案:在block外部對(duì)弱化self,再在block內(nèi)部強(qiáng)化已經(jīng)弱化的weakSelf
__weak typeof(self) weakSelf = self;
[self.operationQueue addOperationWithBlock:^{
__strong typeof(weakSelf) strongSelf = weakSelf;
}
}];
4、WKWebView 造成的內(nèi)存泄漏
- 理由: 但是其實(shí) “addScriptMessageHandler” 這個(gè)操作,導(dǎo)致了 wkWebView 對(duì) self 進(jìn)行了強(qiáng)引用,然后 “addSubview”這個(gè)操作,也讓 self 對(duì) wkWebView 進(jìn)行了強(qiáng)引用,這就造成了循環(huán)引用。
- 解決方案: 解決方法就是在合適的機(jī)會(huì)里對(duì) “MessageHandler” 進(jìn)行移除操作。
- (void)viewDidDisappear:(BOOL)animated {
[super viewDidDisappear:animated];
[_wkWebView.configuration.userContentController removeScriptMessageHandlerForName:@"WKWebViewHandler"];
}
5、NSNotification
@property (nonatomic, strong) id observer; //持有注冊(cè)通知后返回的對(duì)象
__weak __typeof__(self) weakSelf = self;
_observer = [[NSNotificationCenter defaultCenter] addObserverForName:@"testKey"
object:nil
queue:nil
usingBlock:^(NSNotification *note) {
__typeof__(self) strongSelf = weakSelf;
[strongSelf dismissModalViewControllerAnimated:YES];
}];
6、加載大圖片或者多個(gè)圖片
[UIImage imageNamed:@""],次方法使用了系統(tǒng)緩存來(lái)緩存圖像,會(huì)長(zhǎng)時(shí)間占用內(nèi)存,最好使用imageWithContentsOfFile方法;
7、ANF的AFHTTPSessionManager
- 在封裝網(wǎng)絡(luò)請(qǐng)求類時(shí)需注意的是需要將請(qǐng)求隊(duì)列管理者AFHTTPSessionManager聲明為單例創(chuàng)建形式。進(jìn)行全局管理,防止內(nèi)存泄漏
8、地圖類
- 理由: 若項(xiàng)目中使用地圖相關(guān)類,一定要檢測(cè)內(nèi)存情況,因?yàn)榈貓D是比較耗費(fèi)App內(nèi)存的。
- 解決方案: 因此在根據(jù)文檔實(shí)現(xiàn)某地圖相關(guān)功能的同時(shí),我們需要注意內(nèi)存的正確釋放,大體需要注意的有需在使用完畢時(shí)將地圖、代理等滯空為nil,注意地圖中標(biāo)注(大頭針)的復(fù)用,并且在使用完畢時(shí)清空標(biāo)注數(shù)組等。
9、MKMapView
三、iOS內(nèi)存泄露檢測(cè)
參考文檔
iOS 內(nèi)存泄漏排查方法及原因分析
iOS 內(nèi)存泄漏的幾種原因
iOS內(nèi)存相關(guān)的知識(shí)點(diǎn)整理
iOS之NSTimer循環(huán)引用的解決方案
iOS內(nèi)存泄露檢測(cè)