多執行緒導致的iOS閃退分析
前段時間做了一個APP,在測試的時候遇到了很奇怪的閃退情況。
這個APP是有關聲音處理的:裝置一邊錄音,一邊對聲音進行處理。所以需要2個執行緒,一個執行緒將錄音儲存下來,另一個處理儲存下來的聲音。測試的時候,會在1~10min之內,不定時、無預兆的出現閃退的情況,報的錯也各不一樣,有的是
1)”NSGenericException ‘Collection was mutated while being enumerated”
或者:
2)”pointer being freed was not allocated”
還有的閃退資訊提示記憶體用的太多:
3)”crash due to memory pressure”
更有的打出了天書:
4)”First throw call stack:
(0x30170ecb 0x3a907ce7 0x301709b9 0x4a177 0x40a97 0x30b5bab5 0x3013bf0f 0x3013bb2b 0x30139eb3 0x300a4729 0x300a450b 0x350036d3 0x32a05871 0x4f4b9 0x3ae05ab7)”
而時間要求又比較急,真是有點焦頭爛額。經過1天多的研究,這些問題被一一搞定。
首先,第3條,明顯是生成了記憶體而沒有釋放。咦,Objective-C不是有ARC嗎,自動處理記憶體啊,好長時間都沒有因為記憶體煩惱了。但是聲音的處理都是比較底層的,用的都是C語言,對這部分的記憶體,ARC就愛莫能助了。處理起來也不麻煩了,先用Instruments定位一下,哪邊洩漏的記憶體,然後對所有malloc出來的記憶體塊,用完了都free掉。再試一下,記憶體的增加果然慢下來了。
第1條,”Collection was mutated while being enumerated”,意思是,一個物件(一般是NSArray什麼的)在被訪問的時候,這個物件發生了變化,導致程式掛掉了。在我的程式裡,這個物件就是儲存聲音資料的東西,暫且叫它data。第1個執行緒會源源不斷的向data裡寫入新資料,並將舊資料刪掉。而第2個執行緒,則會定時讀取data的內容並做處理。因為這兩個執行緒每次操作data的時間都比較短,所以它們同時操作的情況不是很常見,所以一般程式也能堅持個幾分鐘。然而它們一旦同時對data進行操作/訪問,程式就掛了。
解決方法也很簡單,Objective-C裡有一個語法,專門處理這樣的事:@synchronized(引數){程式碼塊}
當兩個@synchronized程式碼塊的引數相同的時候,這兩個程式碼塊是不能同時操作的。對於引數,我們經常使用self來做引數。例如:
執行緒1:
@synchronized(self){
//寫data
}
執行緒2:
@synchronized(self){
//讀data
}
當執行緒1在寫data時,執行緒2只能等著。這樣就避免了同時多執行緒同時讀/寫global資料塊會出現的閃退問題。
第2條,”pointer being freed was not allocated”,也是因為多執行緒同時寫data的問題,但有一些特殊。data裡只包含了最近一段時間的聲音資料,當data儲存的太多了,就會先將舊資料刪了,再將新資料存起來。問題是執行緒1的呼叫次數非常快,達到1秒鐘50次。有時候上一次呼叫a還沒結束,下一次呼叫b又過來了,這時候就可能會出問題:a檢測到data裡的資料太多了,就將最舊的資料刪了。然而沒等a真正將資料刪除,b又來了,它也要將最舊的資料刪了,這樣同一個資料就要被free兩次,編譯器就要叫:尼碼這個指標裡已經空了,你還要老子再free它,老子不幹了!
解決方法同上,也加一個@synchronized,將這段資料塊包起來,告訴編譯器:為了保證服務質量,每次只向一個執行緒提供服務,等上一位大爺舒坦了,再讓下一個進來。
最後,有時候編譯器還會抽風,只告訴你,”我要掛了!”(EXC_BAD_ACCESS),然後嘔吐出一大堆排洩物:
“First throw call stack:
(0x30170ecb 0x3a907ce7 0x301709b9 0x4a177 0x40a97 0x30b5bab5 0x3013bf0f 0x3013bb2b 0x30139eb3 0x300a4729 0x300a450b 0x350036d3 0x32a05871 0x4f4b9 0x3ae05ab7)”
作為程式設計師,我們要從這堆排洩物中找到編譯器的病因,看看它到底吃了啥:
在AppDelegate.m里加入這個函式:
void uncaughtExceptionHandler(NSException *exception) {
NSLog(@”CRASH: %@”, exception);
NSLog(@”Stack Trace: %@”, [exception callStackSymbols]);
//Internal error reporting
}
然後:
– (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
NSSetUncaughtExceptionHandler(&uncaughtExceptionHandler);
}
這樣,當編譯器掛了的時候,就會打印出這樣的東西:
0 CoreFoundation 0x30c16f9b <redacted> + 154,
1 libobjc.A.dylib 0x3b491ccf objc_exception_throw + 38,
2 CoreFoundation 0x30b4da39 <redacted> + 176,
3 TEST 0x001ce2c9 -[TestBaseViewController viewDidLoad] + 848,
我們就能看到,問題出在[TestBaseViewController viewDidLoad]函式裡(請忽略後面的+848,我不知道是什麼意思,貌似也沒人知道)。雖然無法定位到具體哪一行,但至少是大大縮小的範圍。
另外,還有一個關於崩潰定位的小技巧:在所有你懷疑會出現閃退的地方附近,瘋狂的NSLog,這樣,當閃退的時候,很快就能定位到在哪個位置閃退了。
對於程式設計師來說,定位到問題意味著問題解決了90%。
相關推薦
多執行緒導致的iOS閃退分析
前段時間做了一個APP,在測試的時候遇到了很奇怪的閃退情況。 這個APP是有關聲音處理的:裝置一邊錄音,一邊對聲音進行處理。所以需要2個執行緒,一個執行緒將錄音儲存下來,另一個處理儲存下來的聲音。測試的時候,會在1~10min之內,不定時、無預兆的出現閃退的情況,報的錯
《Exploring in UE4》多執行緒機制詳解[原理分析]
目錄 一.概述 二."標準"多執行緒 三.AsyncTask系統 3.1 FQueuedThreadPool執行緒池 3.2 Asyntask與IQueuedWork 3.3 其他相關技術細節 四.TaskGraph系統 4.1 從Tick函式談起 4.2 T
python多執行緒探討 基於原始碼 初步分析
這篇文章 應該有人需要 因為我現在都需要 所以標了個關鍵字初步 摘自百度百科 儘管提高CPU的時鐘頻率和增加快取容量後的確可以改善效能,但這樣的CPU效能提高在技術上存在較大的難度。實際上在應用中基於很多原因,CPU的執行單元都沒有被充分使用。如果CPU不能正常讀取資料(
python多執行緒的幾種情形分析-三種情況
情形一:預設情況 預設情況,只開啟執行緒,那麼,主執行緒結束,其他子執行緒可能還沒結束。 只使用t=threading.Thead(target=fun),t.start()。 import threading import time def run(): tim
多執行緒計算pi效率對比分析
繼續昨天的計算pi的程式 分配不同的執行緒數量得到的不同的執行時間對比 可以看到很明顯的 從一個執行緒變成兩個執行緒確實時間減少了一般左右,但是繼續增加執行緒數量卻不怎麼影響結果。這是因為我電腦的CPU型號為Intel 酷睿i3 370M,雙核四執行緒 ,所以雙執行緒
Chromium多執行緒模型設計和實現分析
Chromium除了遠近聞名的多程序架構之外,它的多執行緒模型也相當引人注目的。Chromium的多程序架構是為了解決網頁的穩定性問題,而多執行緒模型則是為了解決網頁的卡頓問題。為了達到這個目的,Chromium的多執行緒模型是基於非同步通訊的。也就是說,一個執
ActiveX控制元件中使用多執行緒導致的問題
用VC++6.0寫MFC ActiveX控制元件,就是實現個數據統計功能,呼叫SqlServer的儲存過程,計算量比較大,呼叫時間比較長,所以要把進度顯示出來(方法前文有述),用到多執行緒。需要線上程函式裡把計算的結果通過控制元件事件傳出去。 問題很奇怪,本來以為沒問題,使用
WebView中使用Label標籤導致iOS閃退
在WebView中載入HTML5程式碼:<div class="ui-form-item ui-form-item-show ui-form-item-link ui-border-b upCollPage" data-type="input" onclick=""&g
由多執行緒導致的request請求引數獲取不到問題
症狀: 程式碼還是按照常規寫法寫的,莫名其妙的忽然使用request拿不到引數。 如上面的程式碼,springmvc幫我們
關於ios使用執行緒導致程式不規律的閃退問題解決
之前自己寫的一個小專案,使用支執行緒的目的就是為了一些運算 或者伺服器間的互動。 [NSThreaddetachNewThreadSelector:@selector(setLoadData)toTarget:selfwithObject:nil]; 開啟一個執行緒
iOS的三種多執行緒技術 對比分析
1 #pragma mark 模仿下載網路影象 2 - (IBAction)operationDemo3:(id)sender 3 { 4 // 1. 下載 5 NSBlockOperation *op1 = [NSBlockOperation blockOperationWit
iOS多執行緒中,佇列和執行的排列組合結果分析
本文是對以往學習的多執行緒中知識點的一個整理。 多執行緒中的佇列有:序列佇列,併發佇列,全域性佇列,主佇列。 執行的方法有:同步執行和非同步執行。那麼兩兩一組合會有哪些注意事項呢? 如果不是在董鉑然部落格園看到這邊文章請 點選檢視原文 提到多執行緒,也就是四種,pthread,NSthread,GCD
Objective-C高階程式設計:iOS與OS X多執行緒和記憶體管理
這篇文章主要給大家講解一下GCD的平時不太常用的API,以及文末會貼出GCD定時器的一個小例子。 需要學習的朋友可以通過網盤免費下載pdf版 (先點選普通下載-----再選擇普通使用者就能免費下載了)http://putpan.com/fs/cy1i1beebn7s0h4u9/ 1.G
[讀書筆記]iOS與OS X多執行緒和記憶體管理 [GCD部分]
3.2 GCD的API 蘋果對GCD的說明:開發者要做的只是定義想執行的任務並追加到適當的Dispatch Queue中。 “Dispatch Queue”是執行處理的等待佇列。通過dispatch_async函式等API,在Block
Android多執行緒分析之一:使用Thread非同步下載影象
Android多執行緒分析之一:使用Thread非同步下載影象 羅朝輝 (http://blog.csdn.net/kesalin) CC 許可,轉載請註明出處 打算整理一下對 Android Framework 中多執行緒相關知識的理解,主要集中在 Fra
iOS總結-多執行緒篇之NSOperation和NSOperationQueue
參考:https://www.jianshu.com/p/4b1d77054b35 NSOperation/NSOperationQueue是基於GCD更高一層的封裝,完全面向物件。 優點:1.可新增完成的程式碼塊,在操作完成後執行
iOS總結-多執行緒篇之GCD之三
dispatch_barrier_async :GCD柵欄方法 dispatch_apply dispatch_semaphore:GCD訊號量 持有計數的訊號,計數為0時等待,不可通過.計數為1或者大於1時,計數減1且不等待,可通過. dispatch_semap
iOS總結-多執行緒篇之GCD之二
dispatch_group dispatch_wait dispatch_group_enter/dispatch_group_leave dispatch_group_enter標誌一個任務加入group,未執行完畢任務數+1 dispatch_group
iOS總結-多執行緒篇之GCD之一
程序:作業系統資源分配的基本單位 執行緒:任務排程和執行的基本單位 一個程序裡面可以有多個執行緒. GCD自動利用CPU核心(如雙核,四核),會自動管理執行緒的生命週期(建立執行緒,排程任務,銷燬執行緒) 而NSOperation Queue是可以管理執行緒的. 佇列
iOS - 知識梳理(多執行緒)
多執行緒:一個程序裡面開啟多條執行緒,每條執行緒可以單獨的執行不同的任務。 iOS實現多執行緒的方式: 1、pthread(C寫的、基本不用) 2、NSThread 3、gcd 4、NSOperation 下面分別介紹下後三個常用的多執行緒方式 NSThread: 使用方式