Android内存泄漏分析实战

来源:互联网 发布:阿里域名解析带端口号 编辑:程序博客网 时间:2024/05/16 04:49

   先写一个单例导致的内存泄露demo,刚开始写代码的时候都喜欢往自己写的utils类里面传入当前的Activity,代码很简单,直接贴上代码:

package com.memoryleakdemoimport android.support.v7.app.AppCompatActivity;import android.os.Bundle;public class MainActivity extends AppCompatActivity {    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        CommonUtils.getInstance(this);    }}
package com.memoryleakdemo;import android.content.Context;/** * Created by my on 2017/10/14. */public class CommonUtils {    public static CommonUtils commonUtils;    private Context mContext;    public CommonUtils(Context mContext){        this.mContext=mContext;    }    public static CommonUtils getInstance(Context mContext){        if(commonUtils==null){            commonUtils=new CommonUtils(mContext);        }        return  commonUtils;    }}
运行代码,旋转手机屏幕,此时会销毁并重新创建Activity,因为单例的生命周期是同Application的,单例里持有Activity的引用,所以此时会发生内存泄露。
  我们用Androidstudio自带的Android Monitor分别获取销毁前和重新创建后的hprof文件,该文件包含了内存堆详细的内存信息,如图所示:
    然后借助MAT工具进行分析,MAT只有Eclipse插件没有Android Studio插件,所以需要自己下载。我们将生成的两个hprof文件分别转成MAT支持的文件,为了方便,分别取名

为noleak.hprof,leak.hprof。如图所示:


  打开MAT并且导入刚刚生成的两个文件进行分析:其中histogram里记录了堆里所有分配的对象数


  分别点开它们,并加入对比栏:



  可以看到总共有4728个类,现在只显示了15个类的分配情况,难道要一个个比对过去吗?那也太麻烦了。其实我们可以在最上方的<Regex>里输入我们应用的包名不就可以匹配到我们想查看的类了吗?


  嗯,这下能看出来了,第二个比第一个多了一个MainActivity对象,多了264的堆空间。应该是这个MainActivity没有被及时回收。可这个MainActivity是怎么泄漏的呢。当然这个例子里我们是预先知道的,但是如果不知道呢?怎么查出泄漏的地方?通过【with outgong reference】可以查看MainActivity所有被引用的地方:



  这么多的地方引用到了MainActivity,这可怎么看啊。我们知道java中里有:

  StrongReference,强引用:
回收时机:从不回收 ;              生命周期:JVM停止的时候才会终止
  SoftReference,软引用
回收时机:当内存不足的时候;生命周期:内存不足时终止
  WeakReference,弱引用
回收时机:在垃圾回收的时候;生命周期:GC后终止
  PhatomReference 虚引用
回收时机:在垃圾回收的时候;生命周期:GC后终止

  所以剔除掉这些引用(软引用,弱引用,虚引用)后不就可以看到内存泄漏的地方吗?如图所示:



  此时可以看到CommUtils持有MainActivity对象导致MainActivity无法被GC回收从而导致了内存泄漏,和我们当初设想的一样。 所以平时使用Utils类的时候,为了避免内存泄漏,最好传入Application的上下文进去。

 





原创粉丝点击