当前位置: 代码迷 >> Android >> android中的内存泄露查寻与常见的内存泄露案例分析
  详细解决方案

android中的内存泄露查寻与常见的内存泄露案例分析

热度:30   发布时间:2016-04-28 01:43:01.0
android中的内存泄露查找与常见的内存泄露案例分析

常见的内存泄露查找方法请参见:http://hukai.me/android-performance-patterns/

这篇文章是google发布的android性能优化典范示例,对于渲染、内存GC与电量消耗都做了好的示范。


这里我总结了下,android中常见的内存泄露

1、类中调用registerReceiver后未调用unregisterReceiver().

在调用registerReceiver后,若未调用unregisterReceiver,其所占的内存是相当大的。

这种情况常见于我们在Activity或者Service中动态注册Receiver,动态注册的receiver会放到application中的一个map中,在application的生命周期内一直持有,这种情况下,相当于持有对于Activity的引用,这样就导致内存泄露了。


2、资源对象未关闭导致的内存泄露

典型的是使用sqlite数据库不释放Cursor和网络文件io使用inputstreamoutputstream记得要调用close方法。

在Android中,Cursor是很常用的一个对象,但在写代码是,经常会有人忘记调用close, 或者因为代码逻辑问题状况导致close未被调用----将close语句放入finally代码中。

通常,在Activity中,我们可以调用startManagingCursor或直接使用managedQuery让Activity自动管理Cursor对象。

但需要注意的是,当Activity介绍后,Cursor将不再可用!

若操作Cursor的代码和UI不同步(如后台线程),那没需要先判断Activity是否已经结束,或者在调用OnDestroy前,先等待后台线程结束。


3、Bitmap使用后未调用recycle()

根据SDK的描述,调用recycle并不是必须的。但在实际使用时,Bitmap占用的内存是很大的,所以当我们不再使用时,尽量调用recycle()以释放资源。


4、构造Adapter时,没有使用缓存的convertView

以构造ListView的BaseAdapter为例,在BaseAdapter中提供了方法:

public View getView(int position, ViewconvertView, ViewGroup parent)

来向ListView提供每一个item所需要的view对象。初始时ListView会从BaseAdapter中根据当前的屏幕布局实例化一定数量的view对象,同时ListView会将这些view对象缓存起来。当向上滚动ListView时,原先位于最上面的list item的view对象会被回收,然后被用来构造新出现的最下面的list item。这个构造过程就是由getView()方法完成的,getView()的第二个形参View convertView就是被缓存起来的list item的view对象(初始化时缓存中没有view对象则convertView是null)。由此可以看出,如果我们不去使用convertView,而是每次都在getView()中重新实例化一个View对象的话,即浪费资源也浪费时间,也会使得内存占用越来越大。这种情况不一定为导致严重的内存泄露,会造成内存抖动,毕竟GC回收内存也需要占用cpu资源。ListView回收list item的view对象的过程可以查看:

android.widget.AbsListView.java --> voidaddScrapView(View scrap) 方法。


5、试着使用关于application的context来替代和activity相关的context

这是一个很隐晦的内存泄漏的情况。有一种简单的方法来避免context相关的内存泄漏。最显著地一个是避免context逃出他自己的范围之外。使用Application context。这个context的生存周期和你的应用的生存周期一样长,而不是取决于activity的生存周期。如果你想保持一个长期生存的对象,并且这个对象需要一个context,记得使用application对象。你可以通过调用Context.getApplicationContext() or Activity.getApplication()来获得。

总而言之,想要避免context 相关的内存泄漏 ,记住以下几点:

· 不要对activity 的context 长期引用( 一个activity 的引用的生存周期应该和activity 的生命周期相同)

· 试着使用关于application的 context 来替代和activity相关的context

· 如果一个acitivity 的非静态内部类的生命周期不受控制,那么避免使用它;使用一个静态的内部类并且对其中的activity 使用一个弱引用。解决这个问题的方法是使用一个静态的内部类,并且对它的外部类有一WeakReference,就像在ViewRoot中内部类W所做的就是这么个例子。


6、集合中对象没清理造成的内存泄漏

我们通常把一些对象的引用加入到了集合中,当我们不需要该对象时,并没有把它的引用从集合中清理掉,这样这个集合就会越来越大。如果这个集合是static的话,那情况就更严重了。


7、回调callback与listener的及时释放。

比如某个Activity传递一个listener到一个Service,那么该Service就持有了对这个Activity的引用,如果该Service作为公共服务组件,就会导致该Activity一直没办法被GC回收引发内存泄露。



1楼lfy8076721124小时前
不错 学习了
  相关解决方案