咱们先创立一个内存走漏的比如

首先,创立一个简略Android Java工程,里边有MainActivity和MainActivity2,其间MainActivity2用来模仿Handler的内存和单例内存走漏比如

MainActivity 跳转到MainActivity2

public class MainActivity extends AppCompatActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        findViewById(R.id.bt_go).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent intent = new Intent(getApplication(),MainActivity2.class);
                intent.putExtra("hhh","hhhh");
                startActivity(intent);
            }
        });
    }
}

MainActivity2模仿了handler和单例持有上下文的内存走漏

public class MainActivity2 extends AppCompatActivity {
    //界说Handler目标
    private Handler handler = new Handler() {
        @Override
        //当有音讯发送出来的时分就履行Handler的这个方法
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            Toast.makeText(MainActivity2.this, "数据返回了!", Toast.LENGTH_LONG).show();
            Log.i("MainActivity2", "handleMessage -->" + Thread.currentThread().getName());
        }
    };
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main2);
        //创立单例,引用活动上下文会发现内存走漏
        TestFactory factory = TestFactory.getInstance(MainActivity2.this);
        //handler内存走漏测试
        findViewById(R.id.button).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                processThread();
            }
        });
    }
    private void processThread() {
        //构建一个下载进度条
        Log.i("MainActivity2", "processThread()-->" + Thread.currentThread().getName());
        new Thread() {
            @Override
            public void run() {
                Log.i("MainActivity2", "run()-->" + Thread.currentThread().getName());
                //在新线程里履行长耗时方法
                longTimeMethod();
                //履行结束后给handler发送一个空音讯
                handler.sendEmptyMessage(0);
            }
        }.start();
    }
    //模仿下载文件的长耗时方法
    private void longTimeMethod() {
        try {
            Log.i("MainActivity2", "longTimeMethod-->" + Thread.currentThread().getName());
            Thread.sleep(10000); //10秒钟
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
    @Override
    protected void onResume() {
        super.onResume();
    }
    @Override
    protected void onDestroy() {
        super.onDestroy();
    }
}

单例类

public class TestFactory {
    private Context context;
    private static volatile TestFactory testFactory;
    public TestFactory(Context context) {
        this.context = context;
    }
    public static TestFactory getInstance(Context context) {
        if (testFactory == null) {
            synchronized (TestFactory.class) {
                if (testFactory == null) {
                    testFactory = new TestFactory(context);
                }
            }
        }
        return testFactory;
    }
}

启动项目,翻开Profiler,绑定咱们的进程,进入内存剖析视图,具体运用方法能够参考上一章

内存走漏的主动剖析需求运用第一种Captrue heap dump Captrue heap dump

每点击一次Record,都会记载当时App内存情况,生成一个Heap Dump记载,所以app操作之后点击一次Record,内存情况记载会跟上一次有所不同的。 GC按钮图标是一个垃圾桶:

Android Profiler (二)应用之分析内存泄露

翻开内存监控就能够进行操作了 点击Mainctivity的跳转按钮,跳转到Mainctivity2 , 然后点击履行履行processThread函数的方法,这边能够自己实现,退出HMainctivity2,回到MainActivity。然后回到Android Profile,履行一次GC按钮(模仿GC回收不可达的引用),再点击Record按钮,就会得到一个Heap Dump “记载1”

Android Profiler (二)应用之分析内存泄露

咱们看到,Leaks 数量是2,说明两种情况都内存走漏了

Android Profiler (二)应用之分析内存泄露
依照箭头的顺序点击便能够查看到走漏的目标 能够看出由于单例持有了活动上下文导致无法被毁掉 第二个走漏是hander的这儿就不打开剖析了

Android Profiler (二)应用之分析内存泄露

细心的网友可能会问,除了第一个选项,后边两个做什么的呢? 依据注释说明咱们能够知道主要剖析native和kottlin的内存运用情况,如果用这个查内存走漏需求自己调查数据,不是最优挑选

是不是很简略,你学废了吗?