天天看點

Android Studio 分析記憶體洩漏

簡單回顧下 JAVA 的記憶體回收機制,記憶體空間中垃圾回收的工作由垃圾回收器 (Garbage Collector,GC) 完成的,它的核心思想是:對虛拟機可用記憶體空間,即堆空間中的對象進行識别,如果對象正在被引用,那麼稱其為存活對象,反之,如果對象不再被引用,則為垃圾對象,可以回收其占據的空間,用于再配置設定。

在垃圾回收機制中有一組元素被稱為根元素集合,它們是一組被虛拟機直接引用的對象,比如,正在運作的線程對象,系統調用棧裡面的對象以及被 system class loader 所加載的那些對象。堆空間中的每個對象都是由一個根元素為起點被層層調用的。是以,一個對象還被某一個存活的根元素所引用,就會被認為是存活對象,不能被回收,進行記憶體釋放。是以,我們可以通過分析一個對象到根元素的引用路徑來分析為什麼該對象不能被順利回收。如果說一個對象已經不被任何程式邏輯所需要但是還存在被根元素引用的情況,我們可以說這裡存在記憶體洩露。

下面我們自己寫一個存在明顯的記憶體洩漏的demo,然後通過記憶體分析,定位問題所在。(還是老套路,Activity下有兩個Button,一個Begin一個End)

package test.memoryLeak;

import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.View;

import com.cxq.selftestdemo.R;

import java.util.ArrayList;

public class TestMemoryActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_test_wifi);
    }

    class Person {
        String name;

        Person(String name) {
            this.name = name;
        }
    }

    boolean isRun = true;
    ArrayList<Person> list = new ArrayList<>();
    Thread thread = new Thread(new Runnable() {
        @Override
        public void run() {
            while (isRun) {
                Person s = new Person("test");
                list.add(s);
            }
        }
    });

    /**
     * 按下begin按鈕
     *
     * @param v
     */
    public void begin(View v) {
        thread.start();
    }

    /**
     * 按下end按鈕
     *
     * @param v
     */
    public void end(View v) {
        isRun = false;
    }


    @Override
    public void onDestroy() {
        super.onDestroy();
    }


}
           

很明顯,這段代碼存在記憶體洩漏

while (isRun) {
    Person s = new Person("test");
    list.add(s);
    s=null;
}      

Person對象s雖然在最後被指派成null,但由于list對象仍然持有對象s的引用,是以s一直被建立,并且一直沒有釋放,是以記憶體就洩漏了。

下面講解如何分析記憶體洩漏:

【環境】

1、Android Studio

2、記憶體分析工具MAT(Memory Analysis Tools)

【步驟1】得到hprof檔案

在Android Studio的Android Monitor,選擇你的程序,然後點選左上角第3個圖示, Dump Java Heap

Android Studio 分析記憶體洩漏

這樣在工程目錄下的captrue檔案夾下就會産生hprof檔案,但是這個不是标準的hprof檔案,需要經過轉換才能被MAT打開分析,轉換操作如下

Android Studio 分析記憶體洩漏

自己随便命名,我這邊命名成1.hprof

【步驟2】使用MAT分析記憶體情況

打開MAT,open File,選擇剛才轉換好的标準hprof檔案(我的是1.hprof),打開

Android Studio 分析記憶體洩漏

點選Leak Suspects,裡面會列出問題可疑點,餅圖的下方是可以點的具體描述,我們找到自己寫的那個類相關的可疑點,點選Details

Android Studio 分析記憶體洩漏

進去檢視引用的路徑以及類的配置設定情況

Android Studio 分析記憶體洩漏
Android Studio 分析記憶體洩漏

發現是在一個線程中不斷的建立Person對象導緻記憶體溢出,定位問題所在。

這隻是一個簡單的分析記憶體洩漏的例子,當然在實際工作中,情況也許會比這個複雜,要具體情況具體分析啦。