一概要:
内存泄漏是一些已经不使用的对象,依然占有内存且垃圾回收机制不法回收它们。最终导致常驻内存越来越大
,影响到程序的性能。
在Android 虚拟机中,采用Mark-Sweep方式实现垃圾回收。Mark标记,Sweep检测。虚拟机会从GC Roots开始
遍历,如果某个节点无法找到一条到达GC Roots的路径,则表示该引用无效,可以被回收。内存泄漏就是存在一些
不好的调用,导致一些无效的引用于GC Roots相连,无法被回收。
知道了原因,我们理应在开发中尽量避免这些。但是万一发生了(代码又不是一个人写的),我们要准确找出它们。
所以我们就要用到检测内存泄漏的工具。
转载:
二使用:
实例代码(我们进入主页面后,点击启动TestSecondActivity,然后按返回退出):
Intent intent2 = new Intent(MainActivity.this, TestSecondActivity.class);startActivity(intent2);
public class TestSecondActivity extends AppCompatActivity{@Overrideprotected void onCreate(@Nullable Bundle savedInstanceState) {Create(savedInstanceState);setContentView(R.layout.activity_testsecond);Runnable runnable = new Runnable() {@Overridepublic void run() {LogUtil.i("TestSE", "thread:" + Thread.currentThread() + "start");try{Thread.sleep(80000l);}catch (Exception e){}LogUtil.i("TestSE", "thread:" + Thread.currentThread() + " end");}};new Thread(runnable).start();}
}
我们会通过两种方式,来检测内存泄漏:
#使用MAT用具查找
1,首先打开Android Studio中的Android Device Monitor如下图。
2,打开后会出现下面界面,选中你要检测应用的包名,然后点击下图画圈的地方(Update Heap),会在程序包
名后标记一个图标
3,接下就是我们的操作,,重复启动回退TestSecondActivity 两次,然后再点下图画圈地方(Dump HPROF file)
生成hprof文件。
生成的hprof文件。
4,因为MAT是用于分析java hprof的工具,我们生成的是Android属性的hprof文件,所以我们要转化一下(我将刚刚
生成的文件重名android.hprof)。
Android Sdk中为我们提供了工具。
转化成了java属性的文件java.hprof。
5,使用MAT打开hprof文件,(如果还没有安装MAT的,先下载安装:/)。
打开后如图:
6,之后我们查看内存中的对象,由于我们的内存泄漏一般都发生在Activity中所以我们之查找Activity即可。
点击下图中的QQL图标,输入select * from instanceof android.app.Activity,类似于SQL语句。红色感叹号为执行按钮。
#内存中有两个TestSecondActivity,但是我们已经退出了TestSecondActivity,说明发生了内存泄漏。
#上面有两个属性。Shallow Size对象自身占用大小,不包括引用。Retained Size对象自身大小+ 直接或间接引用对象
的大小。
7,右击TestSecondActivity,—— Path to GC Roots——All Reference。
看到this$0引用了这个Activity,this$0表示内部类意思。Activity被一个内部类引用,而这个内部类又被target(Thread)引用。
从上面的代码可知:
TestSecondActivity中有内部类runnable,而runnable被Thread使用。工作线程Thread需要sleep 80秒。所以导致
TestSecondActivity无法释放。
解决方法。我们在Activity onDestroy中shutdown 线程Thread就可以了(当然先把Thread变成全局变量)
#直接使用Android Studio上的Monitor Memory查找
1,依然是利用上面的代码,运行程序,打开Android Studio的Monitor界面,查看Memory图像。
2,点击下卡车图标(图中1),可以执行一次GC;点击图中2的位置,可以查看hprof文件。(依次点击1,2)
3,查看结果
#同样监听到了TestSecondActivity的内存泄漏。
三注意
Android中内存引起内存泄漏的常见使用。
1,static变量引起的内存泄漏。
因为static生命周期是类加载时开始,类卸载结束。也就是说static变量在程序死亡时才结束。而如果static变量引用
Activity,那么Activity的资源将一直得不到释放。造成内存泄漏。
解决方法,如果需要Context对象,尽量使用getApplicationContext。假如必须使用Activity那么最好在onDestroy方
法中,将Activity引用设置为null。
2,线程造成的内存泄漏。
类似于上面的例子,线程执行时间长,即使Activity结束了任然在执行。因为new Thread生成一个匿名内部类(内部
类的创建必须依靠外部类),因此握有Activity实例,Activity无法释放。AsyncTask更为严重,因为AsyncTask维持一
个生命周期。
解决方法:合理安排线程,控制线程在Activity结束时结束。
3,Bitmap占用过多的内存。
Bitmap解析需要占用内存,但是Android只提供了8M内存给Bitmap,如果Bitmap过多且不能及时的回收。则会造成内
存溢出。
解决方法:及时recycle,加载图片前先适当的压缩图片。
4,资源未被及时关闭造成内存泄漏
例如Cursor,没有及时关闭,会因持有Activity引用,造成内存泄漏。
解决方法:在onDestroy中及时的关闭。
5,Handler的使用
Handler对象会发送Message到MessageQueue,Looper对象会轮询MessageQueue对象去除Message执行。如果
Message对象长时间未被取出执行。则Message对象持有Handler对象,Handler对象持有Activity(可能)。造成泄漏。
解决方法,在onDestroy中,Handler removeMessage。
欢迎指正!
本文发布于:2024-02-04 15:58:21,感谢您对本站的认可!
本文链接:https://www.4u4v.net/it/170711094856890.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
留言与评论(共有 0 条评论) |