Android - 經過真實案例學習解內存泄漏問題,最終發現Android原生Bug

  做爲一個Android新手小白,剛到新公司,最近的工做就是在學習解各種Bug。轉型之初,面臨各類新知識,會有壓力,可是學習的過程是快樂的。android

  上週剛趕上一類bug,就是應用的內存泄漏問題。最終經過前輩的指點,用了兩天的時間(包括今天),來解決了這個問題,並最終發現了Android原生代碼的bug(值得開心......)。所以將學習的過程總結出來,能夠供像我同樣的新人蔘考學習。shell

 

一. 問題發現的背景ide

   QA測試發現,屢次打開Android系統中設置功能裏的某個Activity時,其佔用的資源未能釋放,而且在兩三百次的重複操做後,設置應用發生了Crash的現象。工具

   崩潰的緣由是OOM問題,即佔用的資源因未能被GC回收,致使內存不足,拋出了OOM(Out of Memory)的異常,應用發生Crash。學習

   所以下一步就是RD來解決問題啦!測試

 

二. 須要準備/掌握的工具spa

   沒有工具的配合,你很難輕鬆的應對和解決問題。通過前輩的指導後,開始入手學習使用解此類問題的一系列工具。插件

      1. Adb Shell 命令debug

     Android新手入門必定先從Adb開始,Adb全稱是Android debug bridge,提供不少操做手機的命令,有了它,能夠方便的debug問題。這裏咱們使用的命令以下,3d

     A. adb shell

             進入adb shell,執行如下命令

     B. am start -a "xxx" -d "xxx"

             經過activity manager打開activity,方便屢次測試,調查進程內存佔用狀況

     C. dumpsys meminfo xxx

             查看進程的內存佔用狀況,xxx爲包名

   2. DDMS + MAT工具

       DDMS全稱是Dalvik Debug Monitor Service,通常我用它來查看即時log,這裏的做用是使用DDMS來生成hprof文件,hprof是Android進程的heap快照,有了它,能夠來研究heap中存在哪些object,以及object的引用,研究爲什麼GC沒有回收對象的緣由。

       而MAT工具,正是由Eclipse提供的,能方便分析hprof文件的工具。MAT全稱是Memory Analyzer Tool,內存分析工具,安裝方式是在Eclipse中,選擇install new software,而後提供插件的網址,選擇安裝便可。

   所以這裏咱們的思路是,經過Adb shell命令來測試並重現問題,而後用DDMS來抓取heap快照,使用MAT來分析heap快照,歷來對照代碼解決問題。

 

三. 解決此內存泄漏問題的過程

   1. 重現問題,經過am start命令直接打開此Activity,而後按手機的返回鍵,屢次重複此過程

   2. 在步驟一的過程當中,每次都使用dumpsys meminfo com.android.settings命令,來觀察heap中Activity的數量。

     正常的狀況下,Activity的值應該爲0或1,不該該持續增加,由於按返回後,若是不存在內存泄漏,無用的Activity對象會被GC(垃圾回收)給回收掉。

     但這裏,由於有問題存在,我觀察到的現象是,Activity的數量一直在增加。以下圖所示,heap中Activity的數量變化:

     步驟一操做1次,

         

         操做2次,

         

         操做5次,

         

         能夠明顯的看到問題的發生,即在咱們每次操做過程當中,Activity雖然已經經過返回鍵,不予顯示,可是佔用的資源未能被GC回收,每次操做都會生成一個新的不會且不會被釋放的Activity對象,發生了內存泄漏!

         所以下一步要來解決問題。

   3. 使用DDMS+MAT發現線索,解決問題

         既然現場已經重現,此時咱們須要用DDMS來生成hprof文件,這裏提到一點,若是你使用的都是Eclipse裏安裝的DDMS與MAT工具,在DDMS中點擊生成hprof文件,會自動關聯MAT,使用MAT打開此文件。

         DDMS生成hprof文件,點擊下圖中的2個綠色按鈕,以下,

         

          MAT打開hprof文件,打開時建議選擇第一項,以下,

          

          以後打開後,就能分析heap文件啦。這裏咱們選擇,點擊Dominator Tree,它能列出heap中最大的對象們,

          

           而後在打開的頁面中,選擇你測試時發現問題的Activity(可使用關鍵詞來過濾結果),這裏出問題的Activity是,AppDrawOverlaySettingsActivity(Android原生代碼),其對應的Fragment是DrawOverlayDetails。因爲咱們操做了5次,能夠發現heap中的5個對象存在,都沒有被釋放。

   

         這時要分析其未被釋放的緣由,要使用到MAT的功能來分析對象的引用,由於強引用的對象不會被GC回收。既然這個Activity對象一直存在,就說明必定是有引用存在,致使其未被GC回收。

     個人作法是,右擊object,點擊Merge Shortest Paths to GC Roots -> exclude all phantom/week/soft etc. preferences(由於要排除弱引用,以及軟引用,這些引用包含的對象都會被GC回收,對咱們沒有參考價值)。

     以後即可以發現緣由了,

          

     經過查看其引用,發現存在一個可疑的mSession變量,它屬於Activity的父類,在類中使用了當前的對象,可是一直未能釋放,所以這就是問題的緣由,致使GC未能回收資源。

     知道緣由後,解決的方法便很簡單,就是在按返回鍵,觸發的onStory或onDetach方法中,釋放此mSession對象。最終便能解決問題。

1    @Override
2     public void onDestroy() {
3         super.onDestroy();
4         mSession.release();
5     }

          

最後提交修改,在新的apk測試中,經過Adb shell命令測試發現,Activity數量已維持正常,內存泄漏的問題便也已解決。

 

最後總結,解決內存泄漏的問題,熟練使用命令和工具很重要。有了它們的幫助,能快速的找到線索,再到代碼中去發現問題。固然複雜的問題,遠沒有本文中解決的過程簡單,可是對於新手來講,學習此方法步驟會有很大幫助!

 

                                    - Kevin Song

                                    2016年5月9日

相關文章
相關標籤/搜索