Android實戰——LeakCanary檢測記憶體洩漏
LeakCanary檢測記憶體洩漏
前言
記憶體洩漏對於初學者們可能是一個陌生的詞語,但是卻頻頻發生於自己的軟體上,只不過自己不知道而已。同理,記憶體溢位也是一個道理。而記憶體洩漏和記憶體溢位常常是面試的考題,所以早點掌握是必不可少的
記憶體洩漏的簡介
記憶體洩漏是指:物件在它有限的生命週期結束時,它們將被垃圾回收,如果在回收時,這個物件還被一系列的引用,導致該物件不會被回收,那麼就會導致記憶體洩漏。隨著洩漏的累積,應用將消耗完記憶體,應用的流暢性就會大大減弱
常見的記憶體洩漏有:
- 靜態變數引用導致記憶體洩漏
- 屬性動畫未及時關閉導致的記憶體洩漏
記憶體溢位的簡介
涉及到記憶體洩漏,當然也逃不過記憶體溢位的內容
記憶體溢位是指:程式要求的記憶體,超出了系統所能分配的範圍,從而發生溢位。Android應用程式的預設最大記憶體值為16M,如果你使用的記憶體超過最大值,則會導致應用報錯
常見的記憶體溢位有:
- 圖片過大導致記憶體溢位
LeakCanary的配置與使用
LeakCanary是square公司開發出來的檢測記憶體洩漏的神器,他可以嵌入到我們的應用中,幫助我們自動檢測記憶體洩漏
一、新增依賴
在專案的gradle中新增對LeakCanary的依賴
dependencies {
//記憶體洩漏
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'
}
二、LeakCanary的使用
首先,需要建立一個類繼承自Application,為了讓我們LeakCanary在全域性的Activity中能夠起作用
public class BaseApplication extends Application {
@Override
public void onCreate() {
super.onCreate();
}
}
接著,在Manifests檔案中指定該Application
<application
android:name=".LeakCanary.BaseApplication">
</application>
最後,就是在Application中直接配置我們的LeakCanary
public class BaseApplication extends Application {
@Override
public void onCreate() {
super.onCreate();
//配置LeakCanary
setupLeakCanary();
}
/**
* 配置LeakCanary
*/
private void setupLeakCanary() {
if (LeakCanary.isInAnalyzerProcess(this)) {
return;
}
LeakCanary.install(this);
}
}
到此我們的LeakCanary就已經嵌入成功,就剩測試了
三、測試記憶體洩漏
我們採用靜態變數的記憶體洩漏來作為我們的測試結果,建立一個類,該類的作用可以儲存一個Activity物件到一個ArrayList中,讓Activity一直存在
public class ActivityPool {
public static ActivityPool activityPool = new ActivityPool();
public static ArrayList<Activity> activities = new ArrayList<>();
public static ActivityPool getActivity() {
return activityPool;
}
public static void addActivity(Activity activity) {
activities.add(activity);
}
}
做好了記憶體洩漏類之後,就在我們的主介面中直接使用該類,並將主介面的Activity存放在ArrayList中
public class LeakCanaryActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_leakcanary);
ActivityPool.getActivity().addActivity(this);
}
}
這個時候,我們就已經模擬了記憶體洩漏了,接著,就可以執行程式進行測試了
四、測試結果與分析
我們執行程式進入主介面,那麼主介面的Activity就被儲存起來了,這個時候是沒什麼事情的,因為主介面的Activity還被引用,並不會發生記憶體洩漏。接著,我們退出主介面,按道理是:退出主介面Activity,其生命週期就被結束了,該Activity必須被系統回收,但是我們還留了一手,將它儲存起來了,那麼等待一段時間後,就會在通知欄收到LeakCanary的通知資訊
這個時候,記憶體洩漏報告就出來了,點選通知資訊,進入記憶體洩漏報告分析
結果分析得:
第一部分(ActivityPool類的activities變數)由於第二部分(ArrayList中的某個陣列)和第三部分(陣列中的某個物件) 導致第四部分(LeakCanaryActivity類的例項instance)洩露
這樣我們就可以很容易的定位到記憶體洩漏的部分
上面說到為什麼要在關閉Activity時,等待一段時間才會出現記憶體洩漏報告呢?
原因是:LeakCanary會監聽所有Activity的生命週期,並且在Activity的onDestory函式結束後,將該Activity新增到記憶體洩漏監控佇列中。接著,在後臺執行緒中檢測這個引用是否被清除,如果沒有將會發生GC操作(垃圾回收),如果引用仍然沒有清除,將heap記憶體dump到一個.hprof檔案並存放在手機系統裡,應用會開啟另一個程序來分析該.hprof檔案,最後匯出洩漏引用鏈,傳回應用程式中,通過推送推送出資訊
結語
LeakCanary的使用並不難,重要的是如何排除記憶體洩漏的問題,可能大部分問題還是需要在實戰中才能摸索出來,這裡只是舉一例子,不過通過這篇之後,相信你對記憶體洩漏和溢位都有一個大概的瞭解,對待類似面試題應該是沒什麼問題了