Android Studio 检测内存泄漏与解决方法

本章主要介绍使用Android Studio 检测内存泄漏 、分析内存泄漏原因及解决方法:

如果不懂何为内存泄漏的朋友请先看这篇文章:http://blog.csdn.net/hudashi/article/details/7050885

一、使用Android Studio检测内存泄漏

打开Android Studio,编译代码,在模拟器或者真机上运行App,然后点击 ,在Android Monitor下点击Monitor对应的Tab,进入如下界面:



在Memory一栏中,可以观察不同时间App内存的动态使用情况,点击 可以手动触发GC,点击 可以进入HPROF Viewer界面,查看Java的Heap,如下图:



Reference Tree代表指向该实例的引用,可以从这里面查看内存泄漏的原因,Shallow Size指的是该对象本身占用内存的大小,Retained Size代表该对象被释放后,垃圾回收
器能回收的内存总和。

下面以我自己写的项目为例,来一探内存泄漏检测的方法。
打开Android Studio,编译代码,运行APP,把所有的功能都使用一遍,然后就从Memory Monitor里面观察App的内存使用曲线,突然发现,纳尼!!!怎么内存使用越来越大了,这就很有可能是发生内存泄漏了,然后点击手动进行GC,再点击观看JavaHeap,点击Analyzer Task,Android Monitor就可以为我们自动分析泄漏的Activity啦,分析出来如下图所示



在这里,我们可以看出,有六个地方发生了内存泄漏抓狂!!!接下来就一一探索下泄漏的原因吧!

先从第一个泄漏的Activity开始吧:首先找到该活动被引用的对象(如上图:)

持有该活动的对象是:WebView ,在这里对于 WebView引起内存泄漏的原因及解决方案推荐一篇文章:http://blog.csdn.net/u012210186/article/details/52608090

我这里的解决方法是:将WebView所在的活动单独放在一个进程中:
1.AndroidMainfest.xml文件配置中将WebView所在的Activity  加上:android:process="packagename.web"
<activity
    android:name=".ui.webview.MyWebView"
    android:launchMode="singleTask"
    android:process="packagename.web"
    android:screenOrientation="portrait"/>
2.在该活退出时结束该进程:
结束方法有很多,我是直接在onDestroy() 函数中System.exit(0); 直接退出虚拟机,一了百了,省了很多代码 大笑
@Override
protected void onDestroy() {
    super.onDestroy();
    System.exit(0);
}
注:此时在进入跳转到WebView所在的活动切换时会出现黑屏,这个解决方法就看我上一篇转载的文章:《 activity跳转黑屏处理

好了,到此时,第一个内存泄漏已经解决,那么来看第二个内存泄漏:
按照同样的方法去找原因:结果发现,持有当前活动的对象是一个Fragment的单例,而这个fragment里又出现了WebView.... 尴尬,好吧,犯二了,解决方案同上!

第三个内存泄漏:

泄漏原因:该活动布局使用的是viewpager + fragment,里面有多个fragment可以滑动切换,fragment使用的是单例。由于单例的生命周期是与进程一致的,所以会导致当前活动销毁时,fragment实例还在。

解决方案:在Fragment中的onDestroy()函数中把fragment实例置空:

@Override
public void onDestroy() {
    if (fragment != null ){
        handler.removeCallbacksAndMessages(null);
        handler = null;
        fragment.onDestroyView();
        fragment = null;
    }
    System.gc();
    super.onDestroy();
}

第四个内存泄漏:原因与第三个相同.....再一次犯二了.....抓狂

第五个内存泄漏:

同样到找持有该活动的实例,定位实例中的代码,发现:此处使用了数据库未关闭:
sqLiiteDatabase = SQLiteUitl.getSQLiiteDatabase(context);
private void addSQLite(ArrayList<DataDomain.Mods> data) {
    sqLiiteDatabase.add(data);
}

解决方法:在活动退出中关闭数据库:
@Override
protected void onDestroy() {
    sqLiiteDatabase.close();
    handler.removeCallbacksAndMessages(null);
    handler = null;
    System.gc();
    super.onDestroy();
}

最后一个内存泄漏的地方:

持有该活动的对象是一个非静态的内部类:
当前活动声明了一个静态变量:
public static UpdateActivity activity;
UpdateActivity即为当前的Activity,方便成员变量又被内部类引用,所以造成了内存泄漏。
解决方法:把静态改为非静态即可:
public UpdateActivity activity;

好了,到此为止,这六处引起内存泄漏的地方已经解决完毕,再运行起来APP,那是杠杠地... 得意

其实引起内存泄漏的原因有很多,常见的:

1.BraodcastReceiver,ContentObserver,FileObserver,Cursor在Activity onDeatory或者某类声明周期结束之后一定要unregister或者close掉,否则这个Activity类会被system强引用,不会被内存回收。

2.不要直接对Activity进行直接引用作为成员变量,如果不得不这么做,请用private WeakReference mActivity来做,相同的,对于Service等其他有自己生命周期的对象来说,直接引用都需要谨慎考虑是否会存在内存泄露的可能。

3.对 Context 保持了一个长生命周期的引用。

4.活动退出时handler未清空消息列队,(可以看下,我上面的代码中,在onDestroy()函数中,只要是该活动有用到handler,我都写有:handler.removeCallbacksAndMessages(null);     handler = null;)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值