检测工具
- AndroidStudio3.0以上
- Memory analyzer或者eclipse MAT插件
1.准备工作:
首先我们模拟内存泄漏,如下代码:
ToastUtils.java
public class ToastUtils {
private static final ToastUtils ourInstance = new ToastUtils();
private static Context mContext;
public static ToastUtils getInstance(Context context) {
mContext =context;
return ourInstance;
}
private ToastUtils() {
}
public void showToast(String msg){
Toast.makeText(mContext,msg,Toast.LENGTH_SHORT).show();
}
}
Main2Activity
public class Main2Activity extends AppCompatActivity {
private Handler handler = new Handler(){
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main2);
ToastUtils.getInstance(this).showToast("hahahhaha");
handler.sendEmptyMessageDelayed(1,6000);
}
}
2.开始检测
2.1以Android Profiler运行应用程序,点击如下按钮
2.2选择MEMORY,点击如下按钮
2.3开始进行测试,随便点点我们的应用然后点击下图1按钮请求gc,再点击2获取一份内存快照,如下:
2.4分析生成的文件,生成的文件如下图:
- Alloc Cout 对象数
- Shallow Size 对象占用内存大小
- Retained Set 对象引用组占用的内存
注:如果Alloc Cout 数量不是1的话,可能就发生了内存泄漏
2.4点击保存到本地,文件名为1.hprof
2.5使用hprof-conv命令转成标准的mat文件
命令如下:
hprof-conv -z /Users/cool/me/1.hprof /Users/cool/me/1_mat.hprof
如果找不到hprof-conv命令,请配置一下环境变量,hprof-con为/SDK/platform-tools/下的工具
将1_mat.hprof拖到 Memory analyzer中,或者已安装mat插件的eclipse中
如下:
点击红框中的按钮,再根据泄漏的类名Main2Activity来筛选,
回车,得到下面结果
选中要排查的类,排除软弱虚引用
将得到结果全部展开,如下:
分析此图,我们看到有3个泄漏点,因为内存泄漏是自己模拟的,所以我们很快就能定位到问题,这里假装是真实开发的项目,我们一个一个分析:
- 第一个泄漏点:沿着Main2Activity一直往上追溯,会发现GCRoot为 com.cool.skinresource.ToastUtils,这里的代码写的有问题,打开后发现单例中静态引用Activity实例导致gc无法回收
- 第二个泄漏点:仔细看就知道handler机制导致的内存泄漏,非静态内部类持有外部类Activity的引用导致的
*第三个泄漏点:Toast的内部类mNextView,mView持有了Activity的引用,这里是因为静态的Context才导致的,如果需要解决此泄漏,需要通过反射将mNextView,mView置为null,将引用链打破即刻
将问题解决后再重复此步骤检测,直至没有内存泄漏