iOS八種記憶體洩漏問題
迴圈引用(Retain Cycle)
先簡單說一下什麼是迴圈引用(retain cycle)
假設我們有兩個例項A和B,B是A的一個strong型的property,則B的引用計數是1,當A的需要釋放的時候,A則會呼叫[B release]來釋放B,B的引用計數則減為0,釋放。
可如果這時候將B的一個strong型property指向A,則A與B互相為強引用,問題就來了。因為B強引用A,A的引用計數永遠不會減為0,當A原本的強引用物件被釋放以後,A和B成為了一個相互引用的孤島,永遠不會被釋放了,這就會引起記憶體洩漏。
在上面的例子中,就是一種非常普遍的引用迴圈情況,加入如上程式碼的VC在dismiss或者pop以後,並不會執行dealloc方法,證明記憶體洩漏了。而引起洩漏的原因就是在作為self的property的block中,使用self指標導致self被block強引用,形成引用迴圈。
總結一下出現記憶體洩漏的幾種常見情況
1、Delegate/NSNotification
我們在使用代理設計模式的時候,一定要注意將 delegate 變數宣告為 weak 型別,像這樣
如使用strong或別的型別修飾的話將會導致迴圈引用,導致dealloc()不會被呼叫。NSNotification沒有移除通知等都會觸發一些意想不到的後果。
2、Block
目前在專案中出現的記憶體洩漏大部分是因為block的問題。
在 ARC 下,當 block 獲取到外部變數時,由於編譯器無法預測獲取到的變數何時會被突然釋放,為了保證程式能夠正確執行,讓 block 持有獲取到的變數,向系統宣告:我要用它,你們千萬別把它回收了!然而,也正因 block 持有了變數,容易導致變數和 block 的迴圈引用,造成記憶體洩露
[_sortButton setButtonSpreadPreAction:^BOOL{
if (_resultItems.count == 0) {
[progressHUD showText:@"xxxx"];
return NO;
}
return YES;
}];
這個例子的問題就在於在使用 block 的過程中形成了迴圈引用:self 持有 sortButton;sortButton 持有 block;block 持有 self。三者形成迴圈引用,記憶體洩露。
GCD已經一些系統級的API並不會提示迴圈引用的警告,但通過測試發現,大部分系統提供block也是需要弱引用的__weak typeof(self) weakSelf = self;
專案中除了AFN的第三方元件在呼叫block時都是需要弱引用的。
3、NSTimer
NSTimer在釋放前,一定要呼叫[timer invalidate],不呼叫的後果就是NSTimer無法釋放其target,如果target正好是self,則會導致引用迴圈。
– (void)performSelector:(SEL)aSelector withObject:(id)anArgument afterDelay:(NSTimeInterval)delay
官方文件是這樣說的:
This method sets up a timer to perform the aSelector message on the current thread’s run loop. The timer is configured to run in the default mode (NSDefaultRunLoopMode). When the timer fires, the thread attempts to dequeue the message from the run loop and perform the selector. It succeeds if the run loop is running and in the default mode; otherwise, the timer waits until the run loop is in the default mode.
大概意思是系統依靠一個timer來保證延時觸發,但是隻有在runloop在default mode的時候才會執行成功,否則selector會一直等待run loop切換到default mode。根據我們之前關於timer
的說法,在這裡其實呼叫performSelector:afterDelay:同樣會造成系統對target強引用,也即retain住。這樣子,如果selector一直無法執行的話(比如runloop不是執行在default model下),這樣子同樣會造成target一直無法被釋放掉,發生記憶體洩露。怎麼解決這個問題呢?其實很簡單,我們在適當的時候取消掉該呼叫就行了,系統提供了介面:
+ (void)cancelPreviousPerformRequestsWithTarget:(id)aTarget
這裡要補充一點,引用迴圈不是隻能有兩個物件,三個四個更多都是可以的,甚至環數也不一定只有一個,所以要養成良好的程式碼習慣,在NSTimer停用前呼叫invalidate方法。
4、Image記憶體過大
5、Foundation與CoreFoundation的相互引用也會造成記憶體洩漏
6.AFN 的NSURLSession不能釋放
//解決辦法:
//修改AFHTTPSessionManager 的manager方法,替換manager;
//或繼承其,自己寫個manager方法
//另一種寫法,兩個單例:
+ (AFHTTPSessionManager *)sharedHTTPSession{
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
manager = [AFHTTPSessionManager manager];
manager.requestSerializer.timeoutInterval = 30;
[manager.requestSerializer setValue:@"XMLHttpRequest"
forHTTPHeaderField:@"X-Requested-With"];
});
return manager;
}
+ (AFURLSessionManager *)sharedURLSession{
static dispatch_once_t onceToken2;
dispatch_once(&onceToken2, ^{
urlsession = [[AFURLSessionManager alloc] initWithSessionConfiguration:
[NSURLSessionConfiguration defaultSessionConfiguration]];
});
return urlsession;
}
7.UIWebView 不能釋放
目前只能用WKWebView 了。其他方法試了下,都沒什麼用
WKWebview也會造成記憶體洩漏,在OC與JS互相呼叫時,
– (void)addScriptMessageHandler:(id <WKScriptMessageHandler>)scriptMessageHandler name:(NSString *)name;
如果不remove掉會使得此VC不走dealloc
感謝微辣小龍蝦的指點
8.友盟分享(無解)
相關文章
- ThreadLocal記憶體洩漏問題thread記憶體
- redisson記憶體洩漏問題排查Redis記憶體
- iOS檢測記憶體洩漏iOS記憶體
- 解決記憶體洩漏(1)-ApacheKylin InternalThreadLocalMap洩漏問題分析記憶體Apachethread
- 記憶體洩漏問題分析之非託管資源洩漏記憶體
- BufferedImage記憶體洩漏和溢位問題記憶體
- 關於PHP記憶體洩漏的問題PHP記憶體
- 如何解決JVM OutOfMemoryError記憶體洩漏問題?JVMError記憶體
- 分析記憶體洩漏和goroutine洩漏記憶體Go
- 分析ThreadLocal的弱引用與記憶體洩漏問題thread記憶體
- 記憶體洩漏引起的 資料庫效能問題記憶體資料庫
- js記憶體洩漏JS記憶體
- Android記憶體洩漏Android記憶體
- Android 記憶體洩漏Android記憶體
- jvm 記憶體洩漏JVM記憶體
- Java記憶體洩漏Java記憶體
- 對於記憶體洩漏問題的簡單認知記憶體
- C++--問題27--如何檢測記憶體洩漏C++記憶體
- 記憶體洩漏的原因記憶體
- valgrind 記憶體洩漏分析記憶體
- 【記憶體洩漏和記憶體溢位】JavaScript之深入淺出理解記憶體洩漏和記憶體溢位記憶體溢位JavaScript
- iOS效能優化 - 工具Instruments之Leaks記憶體洩漏iOS優化記憶體
- JVM——記憶體洩漏與記憶體溢位JVM記憶體溢位
- 使用 Chrome Dev tools 分析應用的記憶體洩漏問題Chromedev記憶體
- MAT工具定位分析Java堆記憶體洩漏問題方法Java記憶體
- 阿里二面:談談ThreadLocal的記憶體洩漏問題?問麻了。。。。阿里thread記憶體
- Android記憶體洩漏場景Android記憶體
- PHP 記憶體洩漏分析定位PHP記憶體
- 記憶體洩漏除錯工具記憶體除錯
- ThreadLocal真會記憶體洩漏?thread記憶體
- WebView引起的記憶體洩漏WebView記憶體
- Perfdog 玩轉記憶體洩漏記憶體
- JavaScript之記憶體洩漏【四】JavaScript記憶體
- .Net程式記憶體洩漏解析記憶體
- 記憶體的分配與釋放,記憶體洩漏記憶體
- 1.記憶體優化(一)記憶體洩漏記憶體優化
- JavaScript之記憶體溢位和記憶體洩漏JavaScript記憶體溢位
- 線上問題排查例項分析|關於Redis記憶體洩漏Redis記憶體
- 線上問題排查例項分析|關於 Redis 記憶體洩漏Redis記憶體