1. 程式人生 > >MemoryMonitor--記憶體清理和Pss監控工具

MemoryMonitor--記憶體清理和Pss監控工具

MemoryMonitor

一個給開發者使用的Android App記憶體清理、監控工具,可以獲取當前手機的記憶體使用比率,可用記憶體大小,檢查一個APP是否存在記憶體洩漏。

並且整理了一些優化記憶體的方式。

0.GitHub地址

1.記憶體清理

類似360衛士的 加速球,獲取系統已用記憶體比率、可用記憶體大小,一鍵清理。

可以用於測試自己開發的Activity、Fragment健壯性,模擬Activity、Fragment被回收的場景,測試自己的程式是否完好的儲存、恢復當前場景。

比如:開啟你開發的某個Activity、Fragment,切到後臺,清理一次記憶體,在將其切回前臺後,看會不會出現空指標異常,以及程式狀態是否被恢復。

2.記憶體監控

Android系統中的記憶體和Linux系統一樣,存在著大量的共享記憶體。每個APP佔記憶體會有私有和公共的兩部分,我們可以通過App的Pss值,可以獲取到這兩部分記憶體。

Pss(Proportional Set Size):實際使用的實體記憶體,即:自身應用佔有的記憶體+共享記憶體中比例分配給這個應用的記憶體。

通過改程式,每隔1秒,獲取一次被監控App的Total Pss值。

使用某個功能(可能會導致OOM的那些都要試試),檢視Pss是否飆升,或者使用過許久都沒有降低。

如果使用後飆升並且長時間都降不下來,那就說明肯定會導致OOM(物件使用過之後還被引用著未釋放),如果使用之後Total Pss飆升,但是使用過之後能降下來,也可能會導致OOM,我們還是需要去一點一點排查是什麼原因導致的。

如果使用後飆升並且長時間都降不下來,我們就需要使用MAT來進一步分析問題所在。

3.記憶體優化

Android的虛擬機器是基於暫存器的Dalvik,它的最大堆大小一般比較小(最低端的裝置16M,後來出的裝置變成了24M,48M等等),因此我們所能利用的記憶體空間是有限的。如果我們使用記憶體佔用超過了一定的限額後就會出現OutOfMemory的錯誤。

可能會導致記憶體溢位的情況有以下幾種:

1)對靜態變數的錯誤使用

如果一個變數為static變數,它就屬於整個類,而不是類的具體例項,所以static變數的生命週期是特別的長,如果static變數引用了一些資源耗費過多的例項,例如Context,就有記憶體溢位的危險。

這種情況:

靜態的sBackground變數,雖然沒有顯式的持有Context的引用,但是: 當我們執行view.setBackgroundDrawable(Drawable drawable);之後。 Drawable會將View設定為一個回撥(通過setCallback()方法),所以就會存在這麼一個隱式的引用鏈:Drawable持有View,View持有Context sBackground是靜態的,生命週期特別的長,就會導致了Context的溢位。

解決辦法: 1.不用activity的context 而是用Application的Context; 2.在onDestroy()方法中,解除Activity與Drawable的繫結關係,從而去除Drawable對Activity的引用,使Context能夠被回收;

2)長週期內部類、匿名內部類長時間持有外部類引用導致相關資源無法釋放

長週期內部類、匿名內部類,如Handler,Thread,AsyncTask等。

HandlerOutOfMemoryActivity所示的是Handler引發的記憶體溢位。

ThreadOutOfMemoryActivity所示的是Thread引發的記憶體溢位。

AsyncTaskOutOfMemoryActivity所示的時AsyncTask引發的記憶體溢位。

3)Bitmap導致的記憶體溢位

一般是因為嘗試載入過大的圖片到記憶體,或者是記憶體中已經存在的過多的圖片,從而導致記憶體溢位。

4)資料庫Cursor未關閉

正常情況下,如果查詢得到的資料量較小時不會有記憶體問題,而且虛擬機器能夠保證Cusor最終會被釋放掉,如果Cursor的資料量特表大,特別是如果裡面有Blob資訊時,應該保證Cursor佔用的記憶體被及時的釋放掉,而不是等待GC來處理。

5)單例模式引用Context導致的記憶體洩露

如果在某個Activity中使用 Singleton instance = Singleton.getInstance(this); 就會造成該Activity一直被 Singleton引用著,不能釋放。這時候,正確的做法是使用 getApplicationContext() 來替代 Activity的Context ,這樣就能避免記憶體洩露。

6)程式碼中一些細節

  • 儘量使用9path
  • Adapter要使用convertView
  • 各種監聽,廣播等,註冊的同時要記得取消註冊
  • 使用完物件要及時銷燬,能使用區域性變數的不要使用全域性變數,功能用完成後要去掉對他的引用
  • 切勿在迴圈呼叫的地方去產生物件,比如在getview()裡new OnClicklistener(),這樣的話,拖動的時候會new大量的物件出來。
  • 使用Android推薦的資料結構,比如HashMap替換為SparseArray,避免使用列舉型別(在Android平臺,列舉型別的記憶體消耗是Static常量的的2倍)
  • 使用lint工具優化工程
  • 字串拼接使用StringBuilder或者StringBuffer
  • 儘量使用靜態匿名內部類,如果需要對外部類的引用,使用弱引用
  • for迴圈的使用 用 final int size = array.length; for(int i = 0; i< size;i++) 來替代: for(int i =0;i < array.length;i++)

最後。

我整理了一些開發中可能會導致記憶體溢位的情況,放在com.cundong.memory.wrong中,並且給出了優化方法,放在com.cundong.memory.right中。

4.截圖

截圖