Android內存泄漏分析
本文轉載自:http://www.apkbus.com/home.php?mod=space&uid=705730&do=blog&id=61605
Android中的內存分爲:
- native進程:採用C/C++實現,不包含dalvik實例的進程。
- java進程:Android中運行於dalvik虛擬機之上的進程。每一個java進程都是存在於一個native進程中。
內存空間是一定的,所以在對象無用時就要回收一些對象來留出空間。當Java Garbage Collection開始運行時,它會從他了解還存活的對象作爲內存遍歷的根節點(GC Root),遍歷heap內存空間,沒有直接或間接引用到GC Root的對象便會被回收。
而Android內存泄漏便是指進程中的對象,雖然沒有使用價值了,但它仍然有直接或間接的引用到GC Root,那麼該對象便不會被GC回收,導致內存持續被佔用,使可用內存變小。
常見的內存泄漏
- 查詢數據庫沒有關閉Cursor。
- 使用BaseAdapter作爲適配器時沒有複用convertView。可以參考ListView與BaseAdapter優化.
- bitmap沒有回收,可以參考Bitmap相關:管理Bitmap內存.
- 註冊對象後沒有反註冊,比如Broadcast Receiver等。
- handler問題,如果handler是非靜態的,會導致Activity或者Service不被回收,所以應當註冊爲靜態內部類,同時在onDestroy時停止線程:
mThread.getLooper().quit();
- Activity被靜態引用,特別是緩存bitmap時,解決方法可以考慮使用Application的context代替Activity的context。
-
View在callback中被引用,可能回調還沒有結束,但是view處於引用狀態,無法回收
public void leak(final View view) { api.callback(new callBack() { onCallBack() { ... } ) }
- WebView的泄露問題:在魅族上面發現webView打開再關閉就會內存泄露..目前使用的解決方法是在webview外面嵌套一層layout作爲container.在Activity的
onDestroy
中調用container.removeAllViews()
方法. - Dialog導致Window泄露,如果需要在dialog依附的Activity銷燬前沒有調用dialog.dismiss().會導致Activity泄露
檢測內存泄露的方法
-
Android Studio 自帶的 Memory Monitor,手動觸發GC可以看得比較直觀,但是dump出來的文件需要處理才能用MAT打開,利用
sdk/platforms-tool/
下的 hprof-conv 文件,命令爲:/hprof-conv source output
-
MAT這篇文章分析得比較透徹
- Leakcanary,檢測一些容易忽略的內存泄露很好用.
adb shell dumpsys meminfo [包名]
可以看到內存使用情況.
一些值得注意的地方
-
理論上來說,當你退出一個 Activity 後,強制GC一次,內存值應該回到跟進入 Activity 差不多的狀態,否則就有可能是內存泄露了.但是有可能是圖片加載庫中對新 Activity 中加載的圖片做了內存緩存,然而這部分內存 GC 可能暫時不會回收.
比如在應用中我使用了 Fresco 去加載本地圖庫中的圖片, Fresco 對這些圖片做了內存緩存,然而這部分的圖片其實是不需要在內存中緩存的.
推薦: