一個給開發者使用的Android App內存清理、監控工具
一個給開發者使用的Android App內存清理、監控工具,可以獲取當前手機的內存使用比率,可用內存大小,檢查一個APP是否存在內存泄漏,并且整理了一些優化內存的方式。
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,就有內存溢出的危險。
Google開發者博客,給出了一個例子:http://android-developers.blogspot.jp/2009/01/avoiding-memory-leaks.html
專門介紹長時間的引用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)代碼中一些細節
- 盡量使用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中。
來自:http://my.oschina.net/liucundong/blog/398547