Android 內存泄漏分析
為什么會內存泄漏?
一個不會被使用的對象,因為另一個正在使用的對象持有該對象的引用,導致它不能正常被回收,而停留在堆內存中,內存泄漏就產生了;
引用分類:
1.強引用
以前我們使用的大部分引用實際上都是強引用,這是使用最普遍的引用。例如使用new創建對象 ,匿名內部類/非靜態內部類和異步線程,默認都會持有外界的引用;
2.軟引用(SoftReference)
如果一個對象只具有軟引用,那就類似于可有可物的生活用品。如果內存空間足夠,垃圾回收器就不會回收它,如果內存空間不足了,就會回收這些對象的內存。只要垃圾回收器沒有回收它,該對象就可以被程序使用。軟引用可用來實現內存敏感的高速緩存, 軟引用可以加速JVM對垃圾內存的回收速度,可以維護系統的運行安全,防止內存溢出(OutOfMemory)等問題的產生。
3.弱引用(WeakReference)
如果一個對象只具有弱引用,那就類似于可有可物的生活用品。弱引用與軟引用的區別在于:只具有弱引用的對象擁有更短暫的生命周期。在垃圾回收器線程掃描它 所管轄的內存區域的過程中,一旦發現了只具有弱引用的對象,不管當前內存空間足夠與否,都會回收它的內存。不過,由于垃圾回收器是一個優先級很低的線程, 因此不一定會很快發現那些只具有弱引用的對象.
4.虛引用(PhantomReference)
虛引用就是GC分分鐘會回收的引用 。虛引用并不會決定對象的生命周期;如果一個對象僅持有虛引用,那么它就和沒有任何引用一樣,在任何時候都可能被垃圾回收。
內存泄漏的幾種情況:
1.單例模式造成的泄漏:
在activity生命周期中使用單例模式的時候 ,當Activity A生命周期結束,但靜態類里面卻還存在activity的引用(mContext),這樣Activity就會占用的內存就一直不能回收,而靜態類的對象也不會再被使用,從而導致內存泄漏;
2.集合造成的泄漏:
集合類如果僅僅有添加元素的方法,而沒有相應的刪除機制,導致內存被占用。如果這個集合類是全局性的變量 (比如類中的靜態屬性,全局性的 map 等即有靜態引用或 final 一直指向它),那么沒有相應的刪除機制,很可能導致集合所占用的內存只增不減。比如我們都喜歡通過 HashMap 做一些緩存之類的事,這種情況就很容易導致泄漏問題。
3.匿名內部類/非靜態內部類導致內存泄漏:
匿名內部類/非靜態內部類和異步線程,默認都會持有外界的引用,如果前者突然因為某種原因要finish,或者activity突然掛掉 , 但是系統判斷還有對象持有,那么就會造成內存泄漏。
4.線程造成的內存泄漏:
當我們在使用線程的時候,一般都使用匿名內部類,而匿名內部類會對外部類持有默認的引用,當Acticity關閉之后如果現成中的任務還沒有執行完畢,就會導致Activity不能正常回收,造成內存泄漏。
5.資源未關閉造成的內存泄漏:
對于使用了BraodcastReceiver,ContentObserver,File,Cursor,Stream,Bitmap等資源的代碼,應該在Activity銷毀時及時關閉或者注銷,否則這些資源將不會被回收,造成內存泄漏
。
6.handler泄漏:
對于handler泄漏其實是由于消息隊列持有對handler的引用,而handler又持有activity的隱式引用,這個引用會保持到消息得到處理,而導致activity無法被垃圾回收器進行回收,而導致內存泄漏 ,使用static+WeakReference可以解決內存泄漏問題,不過不寫也無所謂 , 不加static的默認會在handler構造函數加上activity這個參數,只要handler沒有被回收,就會泄露。加static目的是為了防止泄露,為什么會泄露,就是因為沒回收,沒回收是因為還引用著。只有postDelayed的時候才會有泄露問題,因為delayed的時候activity的引用還保持著,所以只要delayed完了就能回收了,大多數情況下根本不必用加static。
內存檢測工具:
1.Android Studio有一個叫做Android Monitor的內置工具
2.Android studio自帶的功能
檢測過程中電腦會比較卡 , 不實用。
3.第三方檢測工具LeakCanary:
親測很實用 , 缺點就是檢測到有泄漏的時候會延遲幾秒才能推送到,而且會卡一下;
使用步驟 1.添加依賴:debugCompile'com.squareup.leakcanary:leakcanary-android:1.5'
releaseCompile'com.squareup.leakcanary:leakcanary-android-no-op:1.5'
testCompile'com.squareup.leakcanary:leakcanary-android-no-op:1.5'
2.在Application中進行配置:
3.在AndroidManifest.xml里面配置:
4.使用第三方檢測工具FindBugs:
在Android studio下載插件,下載后重啟一下Android studio, 然后會看到紅色的圖標:
點擊運行第五個按鈕:
插件運行幾分鐘后會出現以下結果:
來自:http://www.jianshu.com/p/6cf427ab0085