您的位置:首页 > 移动开发 > Android开发

Android性能优化 -- Memory Monitor工具检测内存泄露

2018-02-02 09:01 513 查看
    这里我们通过一个例子来学习Memory Monitor工具的使用。

示例

package com.android.test;

import android.content.Context;

public class UserManger {

public static UserManger instance;

private Context mContext;

private UserManger(Context context) {
mContext = context;

}

public static UserManger getInstance(Context context) {
if (instance == null) {
instance = new UserManger(context);
}

return instance;
}
}
package com.android.test;

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

public class MainActivity extends AppCompatActivity {

UserManger mUserManager;

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

mUserManager = UserManger.getInstance(this);
}
}
    我们在之前的学习中有说过,内存泄漏产生的原因:当一个对象已经不需要再使用了,本该被回收时,但是因为有另外一个对象持有它的引用,从而导致对象不能被回收,这种导致本该被回收的对象不能被回收而停留在堆内存中,就会产生内存泄漏。

    上面的代码就是一个单例模式内存泄漏的场景,那么这篇博客的目的就是如何把代码中的内存泄漏找出来。

    分析上面的代码,我们知道发生泄漏的不是UserManager,而是MainActivity,知道为什么吗?因为UserManager中有一个静态成员instance,其生命周期和应用程序的生命周期是一致的,当退出应用时,才会被销毁;当MainActivity退出时,有可能发生GC,GC时就会回收MainActivity,因为MainActivity的对象(this)被UserManager对象所引用,UserManager本身是不能被干掉的,所有就会发生内存泄漏。

Memory Monitor

    Android Studio自导的Memory Monitor可以方便的观察堆内存的分配情况,并且可以粗略的观察有没有发生Memory Leak。

Memory Monitor使用

    在Android Studio界面,双击“Shift”键,打开搜索框,输入“Android Monitor”,即可打开Android Monitor界面。

      


        Memory Monitor是Android Monitor中的一种,位于界面中最上面。



水平方向是时间轴,竖直方向是内存的分配情况;
图中深蓝色的区域,表示当前正在使用中的内存总量;浅蓝色或浅灰色区域,表示空闲内存或者叫做未分配内存。
左上角工具栏三个圆圈按钮依次代表:initiate GC、内存快照(Dump Java Heap)、Allocation Tracking。
initiate GC:手动触发GC操作;
Dump Java Heap:获取当前的堆栈信息,生成一个.hprof文件(包名+日期+".hprof"),Android Studio会自动使用HeapViewer打开,一般用于操作之后检测内存泄漏的情况;
Allocation Tracking:内存分配追踪工具,用于追踪一段时间内的内存分配使用情况。能够知道执行某些操作后,有哪些对象被分配空间。

    回到我们的程序,多点击几次GC按钮,看一下这个用于的内存使用情况。



    可以看到现在已经分配的内存有5.69MB,我把手机旋转一下,再点击GC按钮。



    可以看到现在的内存使用量是6.32MB,却明显增加了,这里很关键!!

    接下来,我们找一下哪里发生了内存泄漏。

    点击Dump Java Heap,生成快照文件com.android.test_2018.02.01_16.14.hprof,Android Studio会自动弹出HPROF Viewer来分析它。

HPROF Viewer使用

    下面引用网络一张图片,介绍下HPROF Viewer使用。



HPROF Viewer查看方式

    左上角两个红框,是可选列表,分别是用来选择Heap区域和Class View的展示方式。

    Heap类型分为:

    App Heap:当前App使用的Heap。

    Image Heap:磁盘上当前APP的内存映射拷贝。

    Zygote Heap:Zygote进程Heap(每个APP进程都是从Zygote孵化出来的,这部分基本是framework中的通用类的Heap)。

    Class List View:类列表方式。

    Package Tree View:根据包结构的树状显示。

HPROF Viewer主要分为ABC三大板块

    板块A:这个应用中所有类的名字。

    版块B:左边类的所有实例。

    板块C:在选择B中的实例后,这个实例的引用树。

A板块左上角列名解释





B板块右上角上角列名解释

列名解释
Instance该类的实例
Depth深度, 从任一GC Root点到该实例的最短跳数
Dominating Size该实例可支配的内存大小
B板块右上角有个"的按钮, 点击会进入HPROF Analyzer的hprof的分析界面:



    在这个界面中可以直接把内存泄露可能的类找出来。



    1. 一个Activity应该只有一个实例,但是从A区域来看total count的值为2,heap count的值也为2,说明有一个是多余的。

    2. 在B区域中可以看见两个MainActivity的实例,点击一个看他的引用树情况。

    3. 在C区域中可以看到MainActivity的实例Context,被UserManager的instance引用了,引用深度为1。

    4. 在Analyzer Tasks 区域中,直接告诉你Leaked Activities,MainActivity包含其中。

多方面的证据表明MainActivity发生了内存泄露。

解决方案

public class UserManger {

public static UserManger instance;

private Context mContext;

private UserManger(Context context) {
mContext = context;

}

public static UserManger getInstance(Context context) {
if (instance == null) {
if (context != null) {
instance = new UserManger(context.getApplicationContext());
}
}

return instance;
}
}
    不要用Activity的Context,因为Activity随时可能被回收,我们可以使用Application的Context,Application的Context的生命周期是整个应用。

Allocation Tracker

    Memory Monitor获得内存的动态视图,Heap Viewer显示堆内存中存储了什么,但是Heap Viewer不能显示你的数据具体分配在代码的何处。还有一个功能Allocation Tracker,用来内存分配追踪。

    点击图中Allocation Tracking按钮启动追踪,再次点击停止追踪,随后自动生成一个alloc结尾的文件,这个文件就记录了这次追踪到的所有数据,然后会自动打开一个数据面板。



Allocation Tracker查看方式

    有两种查看方式,默认是Group by Method方式。

    Group by Method:用方法来分类我们的内存分配。

    Group by Allocator:用内存分配器来分类我们的内存分配。

   


    从上图可以看出,首先以线程对象分类,Size是内存大小,Count是分配了多少次内存,点击就可以查看到每个线程里所有分配内存的方法。

关于性能优化内存相关的更多了解可参考:

Android内存优化--OOM 

Android性能优化 -- 内存管理机制
 
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  Android