Android中几种常见的内存泄露以及详细解决方案

内存泄露:当一个对象使用完成后,该被GC回收内存时,由于另一个对象持有它的引用,导致不能被回收,造成内存泄露。(其实就是某个对象所占的内存不能被回收,也就是这块内存被GC“泄露”回收了,就是内存泄露)。
内存泄露在Android中指的是Activity等组件的泄露。
1.Handler
Handler一般用来做耗时任务,有可能会造成内存泄露。一般情况下,我们会创建一个内部类handler(非静态的)去使用。**在java中,非静态内部类或匿名内部类会隐式的持有外部类的引用,**在这里就是Handler默认持有外部类Activity的引用。此时如果关闭Activity,handler中有未发送或未处理完的消息,则message就会持有handler的引用(源码中handler在发送消息时已经将自身与message绑定在一起了,msg.target就是handler,大家可以自行查看一下),而handler又持有activity的引用,导致activity来不及释放(内存不能被系统回收),造成内存泄露。
解决方案:
①创建静态内部类handler(静态内部类不会持有外部类的引用,但也不能调用外部的方法),不过可以在handler内部弱引用化Activity。
在这里插入图片描述弱引用:一方面可以继续持有外部类的引用,即可以调用外部的方法;另一方面GC(垃圾回收器)一旦发现有弱引用对象的存在,不管内存空间是否充足,都会进行垃圾回收。这样“静态+弱引用”可以有效避免内存泄露了。
②将handler创建一个单独的类。(就是创建一个class继承自Handler即可,这里不再展示)。
2.非静态内部类创建的静态实例
非静态内部类或匿名内部类默认持有外部类的引用。如果非静态内部类创建了一个静态实例(或是一个静态变量引用了非静态内部类),静态(static),它的生命周期是和Application的生命周期是保持一致的。若Activity被finish(),静态实例会持有非静态内部类的引用,非静态内部类又持有Activity的引用,因为静态实例的生命周期过长,导致Activity及时销毁时不能被GC回收,造成内存泄露。
解决方案:将非静态内部类改为静态内部类即可。
3.单例(使用Activity的context)
一般情况下,我们创建一些manager的时候会使用到单例模式,它的目的是只提供一个实例供外部访问,保证全局的唯一性;减少对象创建的同时减少内存开支和系统性能开销等。创建单例的核心步骤:1.构造方法私有化;2.创建静态实例对象;3.创建静态方法。在创建静态方法时会传入Context,是为了获取更多的资源、完成和其它组件或服务的交互等。当我们使用单例的时候,如果传入的是Activity的Context,由于Activity的生命周期较短,随时可以销毁等;而单例中的对象生命周期较长,很容易持有Activity的引用,导致Activity不能被系统回收,造成内存泄露。
解决方案:context使用时注意生命周期,尽量传入Application的Context。
4.资源未关闭(File流、Cursor等)
由于File、Cursor等资源文件在使用时大多都用了缓冲,如果不关闭它们,缓冲所占内存不能被回收,很容易造成内存泄露。有时我们会将它们置为null,而不关闭它们,往往会造成内存泄露。
解决方案:在不使用它们的时候,应该及时关闭它们,即调用它的close()函数,以便它们的缓冲及时的被系统回收内存。
在这里插入图片描述
5.创建的listener或监听(BroadcastReceiver、EventBus等)
在Activity中,我们在使用时注册BroadcastReceiver,而如果没在Activity生命周期内调用unRegeisterReceiver()的话,由于BroadcastReceiver不止被Activity引用,还可能会被系统服务等引用,导致BroadcastReceiver无法被回收,而它仍然持有Activity的引用,导致Activity无法被回收,引起内存泄露。
解决方案:注册过的记得在Activity的onDestory()中取消注册(注销)。
在这里插入图片描述
6.线程(AsyncTask等)
AsyncTask是一种异步处理数据的异步类,其中有专门做耗时操作的方法doInBackground()和用来更新UI的方法onPostExecute()。我们在Activity中创建内部类AsyncTask,感觉它的生命周期和activity的生命周期是一致的,其实并不是,AnyncTask会一直执行,直到doInBackground方法执行完成。此时执行cancel操作,它占用的内存会通知进行回收。如果没有执行cancel操作或有时候即使执行了cancel操作,doInBackground()中也有可能存在仍然在执行的任务,如果Activity已经被销毁,仍然执行的任务继续保留AsyncTask的引用,而非静态内部类AsyncTask持有外部类Activity的引用,导致Activity无法被回收,造成内存泄露。
解决方案:使用静态AsyncTask,如果需要用到外部方法的话,在内部添加弱引用化的当前类Activity。
这是自己的分析,有不对的地方还望指出。每天学习一点点。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值