EXC_BAD_ACCESS的本質詳解以及殭屍模式除錯
EXC_BAD_ACCESS簡單理解
當你遇到由EXC_BAD_ACCESS造成的崩潰時,那就意味著你向一個已經釋放的物件傳送訊息。這是最常見的情況。
EXC_BAD_ACCESS的本質
在C和Objective-C中,你一直在處理指標。指標無非是儲存另一個變數的記憶體地址的變數。當您向一個物件傳送訊息時,指向該物件的指標將會被引用。這意味著,你獲取了指標所指的記憶體地址,並訪問該儲存區域的值。
當該儲存器區域不再對映到您的應用時,或者換句話說,該記憶體區域在你認為使用的時候卻沒有使用,該記憶體區域是無法訪問的。 這時核心會丟擲一個異常( EXC ),表明你的應用程式不能訪問該儲存器區域(BAD ACCESS) 。
簡而言之,當你碰到EXC_BAD_ACCESS ,這意味著你試圖傳送訊息到的記憶體塊,但記憶體塊無法執行該訊息。但是,在某些情況下, EXC_BAD_ACCESS是由被損壞的指標引起的。每當你的應用程式嘗試引用損壞的指標,一個異常就會被核心丟擲。
EXC_BAD_ACCESS除錯須知的三點
1、除錯EXC_BAD_ACCESS可能會非常棘手和令人沮喪。
2、你需要知道的是您的應用程式並不一定是在崩潰的那一刻,無法訪問記憶體區域。這就是常使除錯EXC_BAD_ACCESS變得困難的原因。
3、同樣受損指標也是如此。當你的指標被損壞時,您的應用程式不會崩潰。同時,如果您在應用程式中來回傳遞一個受損的指標也不會崩潰。當應用程式試圖引用受損指標的時候,就會發生奔潰。
EXC_BAD_ACCESS除錯——殭屍除錯模式
在Xcode中,您可以啟用殭屍物件,這意味著被釋放的物件將會以殭屍的形式被保留。換言之,保留釋放的物件就是為了除錯。這裡沒有涉及任何魔法。如果您向殭屍物件傳送訊息,你的應用程式將會由於EXC_BAD_ACCESS而崩潰。
這有什麼好處嗎?讓EXC_BAD_ACCESS難以除錯的原因是,你不知道你的應用程式試圖訪問哪個物件。殭屍物件在許多情況下解決這個問題。通過保留已釋放的物件,Xcode可以告訴你你試圖訪問哪個物件,這使的查詢問題原因容易得多。
下面介紹兩種方法來處理BAD_ACCESS:
方案一:
使用Xcode自帶的Instrument,長這個樣子的:
假設現在有一段程式碼存在記憶體洩漏的問題,使用這個工具的步驟如下:
1.設定殭屍物件 (作用是:假設有個物件記憶體被釋放了,但是你想找到問題所在,這個物件就會讓這個物件的記憶體不會被釋放,就像活死人一樣,但是切記,解決問題以後,一定要把殭屍物件去掉,不然會遇到很多莫名其妙的Bug)
如圖所示 開啟scheme:
- 開啟以後介面是這個樣子的,我們使用Instrument 找記憶體洩漏就需要配合殭屍物件,所以接下來我們需要設定殭屍物件;
2.如圖所示 通過這種方式 開啟Instrument
3.開啟的介面是這樣的,按照圖中所示進行選擇:
4.進入這樣的介面,按照圖中所示,進行操作:
然後你就會看到這個程式執行起來後的樣子,如圖所示:
點選你的模擬器 要出問題的地方,把程式搞崩潰,返回到Instrument中,按照下圖進行操作:
點了這個箭頭進去以後,注意到了麼? 有變灰色的行出現了,這就是我們出問題的地方,雙擊這一行進去,就可以定位到我們出問題的地方了:
這裡的例子就是因為,二級頁面中沒有移除通知,導致雖然二級頁面pop以後,頁面雖然沒有了,但是這個物件始終沒有釋放掉,仍有一個物件持有他,這就比較尷尬了,就會出現野指標,導致記憶體問題,不論是ARC還是MRC,都要記住,誰汙染誰處理,物件的引用計數為0,才能得到釋放;
—————————————————————————————
方案二:
使用終端命令列加schme的方式進行尋找;
還是使用上面那個例子喲~
- 編輯scheme,如圖所示:
2.注意到了麼?如下圖,你的控制檯多了點東西,兩個箭頭指的東西都是一樣的,我們需要的是前面的那個程序的pid,如1527;
3.執行你的程式,讓它崩潰,在這個例子中,崩潰以後會在控制檯輸出這樣一句話:
message sent to deallocated instance 0x7ff8fdd2f9c0
//0x7ff8fdd2f9c0就是這個物件
4.使用終端,查詢問題:
輸入:sudo malloc_history 1527 0x7ff8fdd2f9c0
第一輸入,會讓你輸入這臺電腦的密碼,輸入就是了,沒有關係的;
5.結尾,是不是和上面我們用Instrument找到的同一個地方呢?一般出問題的程式碼都在| _objc_rootAlloc | class_createInstance | calloc | malloc_zone_calloc 這些程式碼的前面
Xcode分析專案(如果殭屍物件不能解決你的問題)
使用Xcode來分析你的專案,從Xcode的 Product選單選擇 Analyze或按 Shift-Command-B.Xcode的將需要片刻的時間,但是當它完成的時候你會在左邊的 Issue Navigator看到問題列表。由Analyze發現的問題用藍色高亮顯示。
當你點選一個問題,Xcode的會指向問題程式碼塊,這些正是你要的注意的地方。注意,Xcode僅僅是建議。在某些情況下,這是可能的,問題是不相關的,不固定。如果你找不到造成EXC_BAD_ACCESS的錯誤,那就需要你仔細審視Xcode專案,分析其中發現的每一個問題。
概念理解
被釋放的物件為殭屍物件
指向殭屍物件的指標是野指標
空指標 是把指標位 nil,不會報錯
問題:什麼是殭屍物件?什麼是野指標?什麼是空指標?如何避免野指標錯誤?
答:
1. 殭屍物件 已經被銷燬的物件(不能再使用的物件)
2.野指標 指向殭屍物件(不可用記憶體)的指標 給野指標發訊息會報EXC_BAD_ACCESS錯誤
3.空指標 沒有指向儲存空間的指標(裡面存的是nil, 也就是0) 給空指標發訊息是沒有任何反應的
4. 為了避免野指標錯誤的常見辦法: 在物件被銷燬之後, 將指向物件的指標變為空指標