1. 程式人生 > >經驗之道:最有效的iOS記憶體洩漏檢測

經驗之道:最有效的iOS記憶體洩漏檢測

使用instruments工具來更好的除錯我們的工程中新開發或者修改過的模組的記憶體狀況。

iOS裝置效能越來越好,iOS App 也相應的變得越來越龐大,App程式碼的量級也在快速的增長,開發一個小的模組在工程中除錯變的越來越難,通常我們是通過觀察Allocation的記憶體變化高低,或者記憶體分配快照對比來尋找洩漏的情況,但這幾乎是一個讓人抓狂的除錯方法,尤其在非常複雜的專案中,一個模組的推入與推出在Allocation上的變化微乎其微,而且受制於專案的複雜度,各種你所未知的物件的建立與銷燬帶來的Allocation圖形高度的影響,對於觀察Allocation的分配影象的高低變化來說,能夠參考的意義就變的非常有限。

通過過去參與過的複雜大型的iOS專案開發經驗,開發新的模組的時候,總結出了一套完整的iOS記憶體自測的方法,通過Instruments來逐步跟蹤檢測我們建立和主動銷燬的物件是否真的銷燬了。

在演示之前,需要強調一件事情就是,以資料夾目錄作為你的空間命名很重要,請遵循開發新模組的時候使用你的模組的命名作為字首。因為iOS沒有名稱空間這個東西,通常為了保證不衝突,我們都是以專案字首+空間命名來保證檔案的獨立性,空間名就是目錄和模組的名字了。這個在我們使用instruments進行記憶體檢測的時候是非常重要的,接下來的使用過程就可以證實這一良好的命名習慣所帶來的巨大好處,不只是優雅,更重要的是幫助。

除了命名,還有一件很重要的事情就是,你需要對你的模組在各種UI操作或者事件發生過程的情況下,對你的物件分配過程要非常非常清楚,因為這樣,你才能看出相應的變化,哪些物件是應該存在的,哪些物件在某個動作結束後是必定會銷燬的,這個應該很容易,你應該純天然的就知道,因為你開發的整個邏輯。

最近在開發一個新的模組,正好需要在記憶體方面做一個完整的自測,既要確保效率,也要確保記憶體的正確分配與釋放。

重要:(以下教程開始所有示例圖片,請自行點選圖片看大圖,看的倍兒清楚!)

  1. 首先,我先上圖,看一下我的命名組織結構,遵循的就是模組化的命名,因為手Q的跨部門合作,所以用部門標記作為字首。程式碼首先是要讓人來看的,是人在維護程式,所以可讀性非常重要,在開發完這些功能後,我對於所有物件在執行過程中的建立與銷燬是很清楚的。

  2. 接下來我要進入instruments來進行記憶體測試,profile執行Leaks就OK了,就會進入下面看到的介面,詳細講解一下都是什麼吧,這些對物件怎麼分配記憶體的很重要。

  3. 然後我就需要操作模擬器來進入我所開發的功能模組,會看到非常複雜的物件分配情況,所以這一步非常關鍵,我只需要在搜尋框搜尋模組的字首就可以只顯示當前模組所涉及的物件分配與銷燬情況,如下圖,進入了的模組檢視:

  4. 接下來我執行一個環境查詢的命令,再看一下執行之後的記憶體分配情況。

  5. 我的邏輯是這樣的,點選一次建立一個命令(VASDebugPlatformServerCmd),通過這個命令初始化並執行一個任務,任務結束後就銷燬這個任務物件(VASDebugPlatformBaseOperation),相應的命令也作為任務的成員一起被銷燬。所以,在動作執行完後我們應該可以在已銷燬物件中找到這個例項,執行截圖如下:

  6. 我看到任務是已經被銷燬了的,可是用來初始化的命令物件為什麼沒有被銷燬,我需要深挖一下這個命令物件(VASDebugPlatformServerCmd)的引用計數到底怎麼發生變化的,就需要用到下面的步驟了,按照圖解去深挖它:

  7. 我挖到命令物件的內部,一路挖到底,我發現命令物件最終的引用計數是1,證明它還在記憶體中活著,截圖是這樣的:

  8. 所以,我就看看,任務物件銷燬了,那任務物件到底發生了什麼事 截圖是這樣的:

  9. 我就是不死心,我就是要看到,到底是不是真的呢,為了進一步佐證命令物件在記憶體中,我在物件內部觀察了一個記憶體檢測的通知,收到通知後彈一個alert出來,如果物件被銷燬了,它肯定收不到這個通知,如下面截圖所示的工作:

  10. 因為這是我自己寫的邏輯,我很清楚物件在哪裡分配記憶體,然後我就去查程式碼,命令物件到底經歷了什麼,從開始到結束的執行過程是什麼樣的:


  11. 看完上面的截圖,再去看命令物件的引用計數變化就知道為什麼了:
  12. 當然,我也看出了為什麼引用計數沒有歸零,所以,我在下面進行了修復:
  13. 再次profile->Leaks , 然後我再做一次查詢任務,看看這次命令物件的引用計數變化,命令物件被釋放了!:

總結:

  • 保持你的模組擁有一個良好的名稱空間

  • 請深刻並且清楚的知道,觸發什麼事件,執行UI動作之後,你的物件分配會是什麼樣的,誰此刻應該存在記憶體中,誰應該被銷燬,然後利用上面的原理去檢視,它是不是被銷燬了,如果沒有被銷燬,那麼你應該去查你的程式碼,到底在執行過程中,哪裡沒有平衡引用計數。

  • 此方法在ARC和MRC的情況都是適用的,目標是觀察具體哪個例項物件沒有被銷燬,然後根據引用計數變化跳轉到程式碼中去確認哪裡出現了記憶體問題。

文章來源於公眾號:小時光茶社(Tech Teahouse)