Android Studio 检测内存泄漏与解决方法
16lz
2021-01-22
本章主要介绍使用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"
<activity2.在该活退出时结束该进程: 结束方法有很多,我是直接在onDestroy() 函数中System.exit(0); 直接退出虚拟机,一了百了,省了很多代码
android:name=".ui.webview.MyWebView"
android:launchMode="singleTask"
android:process="packagename.web"
android:screenOrientation="portrait"/>
@Override注:此时在进入跳转到WebView所在的活动切换时会出现黑屏,这个解决方法就看我上一篇转载的文章:《activity跳转黑屏处理》
protected void onDestroy() {
super.onDestroy();
System.exit(0);
}
好了,到此时,第一个内存泄漏已经解决,那么来看第二个内存泄漏: 按照同样的方法去找原因:结果发现,持有当前活动的对象是一个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;)
更多相关文章
- APNS开源包的内存泄露问题
- 记一次java内存分析
- Java对象创建的过程及对象的内存布局与访问定位
- Java并发编程(四)Java内存模型
- java内存垃圾回收模型
- OpenGL es 2.0使用shadow mapping方法制作阴影时,阴影穿透实体现
- 内存探究记录
- MAT:如何诊断“字节”的x实例,由“”占用y (z%)字节的“内存问题
- Android查看应用的最大可用内存及其使用情况