Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> Android開發中的APP內存洩漏檢測

Android開發中的APP內存洩漏檢測

編輯:關於Android編程

使用android shell命令查看內存使用情況

使用adb shell dumpsys meminfo pkgname或者直接使用AndroidStudio裡面的memory usage功能然後就會出現如下信息:

Applications Memory Usage (kB):
Uptime: 14237237 Realtime: 23790474

** MEMINFO in pid 8071 [com.xtc.watch] **
                   Pss  Private  Private  Swapped     Heap     Heap     Heap
                 Total    Dirty    Clean    Dirty     Size    Alloc     Free
                ------   ------   ------   ------   ------   ------   ------
  Native Heap        0        0        0        0    21924     8558     6405
  Dalvik Heap   122472   122372        0    15672   143308    65400    77908
 Dalvik Other    10361    10076      164      224
        Stack      440      440        0        8
    Other dev        4        0        4        0
     .so mmap     6441     3452     2636     2048
    .apk mmap      611        0      340        0
    .ttf mmap      538        0      504        0
    .dex mmap     8407     1640     2940       40
   Other mmap       80        4        0        0
      Unknown    10940    10936        0      148
        TOTAL   160294   148920     6588    18140   165232    73958    84313

 Objects
               Views:      288         ViewRootImpl:        2
         AppContexts:       11           Activities:        2
              Assets:        5        AssetManagers:        5
       Local Binders:       30        Proxy Binders:       38
    Death Recipients:        3
     OpenSSL Sockets:        1

 SQL
         MEMORY_USED:      138
  PAGECACHE_OVERFLOW:       24          MALLOC_SIZE:       62

 DATABASES
      pgsz     dbsz   Lookaside(b)          cache  Dbname
         4       20            306       25/47/12  /data/data/com.xtc.watch/databases/upload.db
Native Heap是native層的內存堆棧,Dalvik Heap是java層的內存堆棧,如果這二者加起來的內存占用超過了應用最大內存限制就會報OOM異常,剩下的.so mmap是 C 庫代碼占用的內存,.jar mmap是Java 文件代碼占用的內存 ,.apk mmap是apk代碼占用的內存,.dex mmap是Dex 文件代碼占用的內存 Objects中的Activities表示當前內存中的activity對象的個數,啟動一個activity就會生成一個activity對象,當退出activity的時候,activity對象就會被釋放,所以反復的進出一個activity界面然後查看Activities的個數有沒有保持不變,如果增加了,那麼就說明這個activity對象沒有被釋放,也就是說可能存在內存洩漏,但是具體哪裡洩漏了並不知道

DDMS查看內存使用情況

eclipse中有一個ddms工具,可以查看線程信息(Threads),內存使用情況(VM Heap),內存分配跟蹤(Allocation Tracker),CUP使用情況(Sysinfo CUP load),內存使用餅狀圖(Sysinfo Memory usage),這裡我們暫時用到VM Heap,選擇要查看的app進程,點擊左上角的show heap updates,選擇VM Heap並點擊Cause GC按鈕,然後就出現下圖:
這裡寫圖片描述
觀察data object的Total Size選項,這個是app的創建的java對象做占用的內存大小,Count是總內存的對象的個數,反復的進出一個activity,看data object的Total Size有沒有明顯的增加,正常情況下進入一個activity的時候會明顯增加,退出一個activity會有明顯的回落,總體是維持在一個比較穩定的水平如果反復進出activity,Total Size不斷上升,那麼可能就存在內存洩漏了,需要具體排查

MAT分析內存洩漏,用AndroidStudio的Monitors的Memory

多點擊幾下Initiate GC來回收一下可被釋放的java對象,因為java的GC是定期有條件執行的,當內存中只存在很少的無用對象,這時候可能並不會觸發GC,所以手動觸發GC來保證開始檢測內存的時候內存都是最干淨的 點擊Dump Java Heap,然後過一會兒就會出現一份數據分析文件,這時候的這份數據文件是剛開始的程序對象內存占用情況,接下去就針對一個activity反復操作進出等等各種反復操作,覺得差不多了,這時候就再次瘋狂點擊Initiate GC回收一下可是放的對象,點擊Dump Java Heap,這時候生成的數據分析文件就是經過你瘋狂操作後的內存占用情況了
這裡寫圖片描述
生成的上述兩個文件右鍵,點擊Export to Standar .hprof導出到一個自己指定的目錄文件夾 去官網上面下載MAT來打開這兩個文件開始內存分析
這裡寫圖片描述
上圖中Problem Suspect部分是代表可能存在內存洩漏的地方,Remainder表示正常的部分,再繼續往下看
這裡寫圖片描述
這裡寫圖片描述
上面就是對可能存在內存洩漏部分的代碼的一個詳細的信息,可以看到有些byte數組占用了大量的內存,keywords也是byte[],第二張圖的DexCache可能占用的較多的內存,再點擊這裡寫圖片描述紅色部分就會出現一些對象的信息列表:
這裡寫圖片描述
可以輸入正則表達式來篩選你想要的類,包名下所有的類,Objects是對象的個數,Shallow Heap是當前對象所占用的內存大小,不包括對象內包含的對象的大小,Retained Heap表示當前對象包括對象內的子對象一共占用的內存大小,所以Retained Heap會比Shallow Heap大得多,對於一些我們已知的對象在內存不洩露的情況下,該對象的個數是確定的,所以可以通過分析Objects的個數來確定對象是否存在內存洩漏,例如同一個Activity對象在反復進出該Activity5次之後Objects的值為5,那就有問題了,說明同一個Activity創建了5個對象,正常情況下應該是退出Activity後,對象會被回收的,所以Objects的值應該是0才對,而有些對象的Objects不為0並不代表一定存在內存洩漏,例如ConnectionService是一個常駐的Service,那麼它是不會被GC的,而ConnectionService裡面的對象可不會被回收,所以這些對象的Objects值不為0其實就是正常的了,至於Shallow Heap和Retained Heap,我覺得可以用來分析一些對象的內存占用,Shallow Heap一般情況下不會很大,當你發現Retained Heap非常大的時候,那就說明該對象裡面的對象可能占用了大量的內存,可能存在問題;在用Objects找到可能存在內存洩漏的對象後,右鍵List Objects,然後有兩個選項:with outgoing references(表示的是當前對象,引用了外部引用)和with incoming references(表示的是當前查看的對象,被外部引用),一般當前對象洩漏了就是對象還被外部對象持有引用,無法被釋放,所以我們選擇查看with incoming references這裡寫圖片描述,點擊with incoming references後
這裡寫圖片描述
可以看到TaskExecutor對象被外部的兩個對象所引用到了,並且可以看到引用的路徑,右鍵TaskExecutor,選擇Path to GC Roots或者或者Merge Shortest Paths to GC Roots選項,再選擇exclude all phantom/weak/soft .ect references排除所有的弱引用,軟引用對象尋找看有沒有存在GC Roots,如果沒有那就說明這個對象不存在內存洩漏,最終是會被GC回收,如果存在GC Roots
這裡寫圖片描述
在繼續查看GC Roots的對象是什麼,其實就是被哪一個對象所引用了,上圖可以查看到被外部的sendTaskExecutor對象所引用了而sendTaskExecutor是在ConnectionService這個常駐Service中的,所以理論上是不應該被回收的,所以這裡不算是內存洩漏,假如sendTaskExecutor是一個Activity裡面的字段,而此時Activity已經退出了,那麼這時候就屬於內存洩漏了,因為Activity退出後,Activity資源包括裡面的對象應該是被回收掉的,那就找到對應的代碼去具體分析可能造成內存洩漏的問題所在了,這裡明確一點,存在GC Roots的不一定就一定存在內存洩漏,GC是不會回收GC Root或者被GC Root所引用的對象的,java對象內存洩漏其實就是對象在不用的時候仍然被其他對象持有引用導致GC無法回收 比較反復操作前的內存信息和反復操作後的內存信息分析前後有哪些不同這裡寫圖片描述,點擊紅色部分後會出現下圖
這裡寫圖片描述
可以看到對比後的Objects和Shallow Heap信息,看Objects表示前後兩種內存信息對於同一個對象是否有個數上的增加,因為如果對象能被正常回收,那麼開始操作前是0,操作後經過GC應該也是0,如果個數增加了,那就表示這個對象可能存在內存洩漏了,拖動到底部可看到總的比較情況
這裡寫圖片描述
上圖可知,操作前的app的Objects總數比操作後的Objects少了1個,同時可以看到是HttpDns這個對象的問題,於是再切換到操作後的histogram去按照上述步驟查找GC Roots,再具體分析內存洩漏的問題 MAT當中還有一個dominator tree視圖,具體就不復述了,可以參考這篇大神文章MAT內存分析

網上的開源項目LeakCanary也是分析內存洩漏的一種有效方法

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved