對于不同的語言平臺來說,進行標記回收內存的算法是不一樣的,像 Android(Java)則采用 GC-Root 的標記回收算法。下面這張圖就展示了 Android 內存的回收管理策略(圖來自Google 2011的IO大會)
圖中的每個圓節點代表對象的內存資源,箭頭代表可達路徑。當圓節點與 GC Roots 存在可達路徑時,表示當前資源正被引用,虛擬機是無法對其進行回收的(如圖中的黃色節點)。反過來,如果圓節點與 GC Roots 不存在可達路徑,則意味著這塊對象的內存資源不再被程序引用,系統虛擬機可以在 GC 過程中將其回收掉。
有了上面的內存回收的栗子,那么接下來就可以說說什么是內存泄漏了。從定義上講,Android(Java)平臺的內存泄漏是指沒有用的對象資源任與GC-Root保持可達路徑,導致系統無法進行回收。舉一個簡單的栗子,我們在 Activity 的 onCreate 函數中注冊一個廣播接收者,但是在 onDestory 函數中并沒有執行反注冊,當 Activity 被 finish 掉時,Activity 對象已經走完了自身的生命周期,應該被資源回收釋放掉,但由于沒有反注冊, 此時 Activity 和 GC-Root 間任然有可達路徑存在,導致 Activity 雖然被銷毀,但是所占用的內存資源卻無法被回收掉。類似的栗子其實有很多,不一一例舉了。
了解完內存泄漏的理論知識后,再來歸類一下內存泄漏的源頭。這里我將其歸位以下三類:
由項目開發人員自身的編碼造成。
這里的第三方代碼包含兩類:第三方非開源的SDK和開源的第三方框架。
由 Android 系統自身造成的泄漏,如像 WebView 、 InputMethodManager 等引起的問題,還有某些第三方 ROM 存在的問題。
內存泄漏不像閃退的BUG,排查起來相對要比較困難些,比較極端的情況是當你的應用 OOM 了才發現存在內存泄漏問題,到了這種情況才去排查處理問題的話,對用戶的影響就太大了。為此,我們能夠在編碼中盡早發現到問題就不要拖到上線之后才去填坑,下面介紹一些我比較常用排查內存泄漏的工具。
Lint 是 Android Studio 自帶的工具,使用姿勢很簡單 Analyze -> Inspect Code 然后選擇想要掃面的區域即可
對可能引起泄漏的編碼,Lint 都會進行溫馨提示。
這里只是拋磚引玉的介紹 Lint ,實際上玩法還有很多,大家可以自行拓展學習。除了 Lint 外,還有像 FindBugs 、 Checkstyle 等靜態代碼分析工具也是很不錯的。
StrictMode 是 Android 系統提供的 API ,在開發環境下引入可以更早的暴露發現問題。
以官網的示例代碼為栗子,一般 StrictMode 只在測試環境下啟用,到了生產環境就會進行關閉,通常我們都會借助 BuildConfig.DEBUG 來實現。
啟用 StrictMode 后,在過濾日志的地方加上 StrictMode 的過濾 Tag ,如果手機連接著電腦進行開發,定期觀察一下 StrictMode 這個 Tag 下的日志,一般你看到一大堆紅色告警的 Log,就需要好好排查一下是否跟內存泄漏有關了。
LeakCanary 和 StrictMode 一樣,需要在項目代碼中集成,不過代碼也非常簡單,如下的官方示例。
build.gradle 引入,Application 中加入兩三行代碼,即可搞定。
我對使用 LeakCanary 有以下兩點感受:
Android 系統本身就存在一些問題導致應用內存泄漏,LeakCanary 的 AndroidExcludedRefs 類幫助我們處理了不少這類問題。
AndroidStudio 提供的工具,用于監控應用的內存使用狀態,在開發中也是非常實用的工具,可以用來打印出內存的狀態信息。
打印獲得的內存信息如下,可以通過右上角的綠色三角形按鈕去分析泄漏的 Activity 和 一些重復的字符串,目前只支持這兩個,希望 Google 后面能夠加入更多可選分析規則
網上關于 MAT 使用的文章好多,大家可以自行查找。上面的 Android Memory Monitor 生成的對儲存信息文件可以配置 MAT 一起來分析使用,由于 Android Memory Monitor 生成的 hprof 文件不是標準格式,所以需要做一下轉換,然后導入 MAT
然后通過 OQL 先定位出泄漏的對象
通過排除除了強引用之外的其他引用鏈,后分析到 GC Root 的位置
MAT 使用起來相對繁瑣,但不失為定位根源問題的利器。
使用 adb shell dumpsys meminfo [PackageName],可以打印出指定包名的應用內存信息
使用該命令可以很直觀的觀察到 Activity 的泄漏問題,是我平常分析比較常用的一種方式。除了使用命令外,AndroidStudio 也提供了下面的功能,和使用命令是一樣效果的。
以上就是我在做內存泄漏分析的時候會用到的工具,通常都是結合起來用,畢每個工具都有優缺點,通過使用多個工具互補分析問題可以極大的提高我們的效率和終取得的效果。
聊完工具,后來談談內存泄漏問題的解決策略。我把它總結為以下三點:
對于如何在編碼上去解決內存泄漏問題,網絡上有提供了很多場景及其解決方案,大家可以自行借助搜索引擎。通過掌握分析方法和對泄漏場景及其解決方案的積累,相信大家處理內存泄漏問題是游刃有余的。當然,也并不是所有內存泄漏問題我們都能夠進行處理,就例如第二章節提到的泄漏源頭是由第三方代碼引起時,我們就顯得無能為力了。近在排查的過程中就發現不少第三方 SDK 存在泄漏問題,遇上這種情況就得找找可替代的 SDK 進行更換了。以上就是我做內存泄漏分析的一些心得總結,如果有錯誤和不足,還請大家指出。
本站文章版權歸原作者及原出處所有 。內容為作者個人觀點, 并不代表本站贊同其觀點和對其真實性負責,本站只提供參考并不構成任何投資及應用建議。本站是一個個人學習交流的平臺,網站上部分文章為轉載,并不用于任何商業目的,我們已經盡可能的對作者和來源進行了通告,但是能力有限或疏忽,造成漏登,請及時聯系我們,我們將根據著作權人的要求,立即更正或者刪除有關內容。本站擁有對此聲明的最終解釋權。