Android导致内存泄漏的几种情形

原创 2016年06月01日 10:53:53

集合类

集合类如果仅仅有添加元素的方法,而没有相应的删除机制,导致内存被占用。如果这个集合类是全局性的变量(比如类中的静态属性,全局性的map等即有静态引用或final一直指向它),那么没有相应的删除机制,很可能导致集合所占用的内存只增不减。

单例模式

不正确使用单例模式是引起内存泄漏的一个常见问题,单例对象在被初始化后将在JVM的整个生命周期中存在(以静态变量的方式),如果单例对象持有外部对象的引用,那么这个外部对象将不能被JVM正常回收,导致内存泄漏。
如果需要Context,尽量引用Application,而不用Activity。

Android组件或特殊集合对象的使用

BroadcastReceiver,ContentObserver,FileObserver,Cursor,Callback等在Activity onDestory或者某类生命周期结束之后一定要unregister或者close掉,否则这个Activity类会被system强引用,不会被内存回收。不要直接对Activity进行直接引用作为成员变量,如果不得不这么做,请用private WeakReference mActivity来做,相同的,对于Service等其他有自己生命周期的对象来说,直接引用都需要谨慎考虑是否会存在内存泄漏的可能。

Handler

Handler的生命周期与Activity不一致

  1. 由于Handler属于TLS(Thread Local Storage)变量,生命周期和Activity是不一致的。
  2. 当Android应用启动的时候,会先创建一个UI主线程的Looper对象,Looper实现了一个简单的消息队列,一个一个的处理里面的Message对象。主线程Looper对象在整个应用生命周期中存在。
  3. 当在主线程中初始化Handler时,该Handler和Looper的消息队列关联(没有关联会报错的)。发送到消息队列的Message会引用发送该消息的Handler对象,这样系统可以调用 Handler#handleMessage(Message) 来分发处理该消息。
  4. 只要Handler发送的Message尚未被处理,则该Message及发送它的Handler对象将被线程MessageQueue一直持有。因此这种实现方式一般很难保证跟View或者Activity的生命周期保持一致,故很容易导致无法正确释放。

handler引用Activity阻止了GC对Acivity的回收

  1. 在Java中,非静态(匿名)内部类会默认隐性引用外部类对象。而静态内部类不会引用外部类对象。
  2. 如果外部类是Activity,则会引起Activity泄露。
  3. 当Activity finish后,延时消息会继续存在主线程消息队列中1分钟,然后处理消息。而该消息引用了Activity的Handler对象,然后这个Handler又引用了这个Activity。这些引用对象会保持到该消息被处理完,这样就导致该Activity对象无法被回收,从而导致了上面说的 Activity泄露。

如上所述,Handler的使用要尤为小心,否则将很容易导致内存泄漏的发生。

错误示例:

    private final Handler mHandler = new Handler() {  
        @Override  
        public void handleMessage(Message msg) {  
            // ...  
        }  
    }; 

解决办法:
使用显形的引用,1.静态内部类。 2. 外部类
使用弱引用 2. WeakReference

正确示例:

    private static class MyHandler extends Handler {  
        private final WeakReference<HandlerActivity2> mActivity;  

        public MyHandler(HandlerActivity2 activity) {  
            mActivity = new WeakReference<HandlerActivity2>(activity);  
        }  

        @Override  
        public void handleMessage(Message msg) {  
            System.out.println(msg);  
            if (mActivity.get() == null) {  
                return;  
            }  
            mActivity.get().todo();  
        }  
    }

    @Override  
    public void onDestroy() {  
        //  If null, all callbacks and messages will be removed.  
        mHandler.removeCallbacksAndMessages(null);  
    }

http://blog.csdn.net/zhuanglonghai/article/details/38233069

ThreadHandler

使用ThreadHandler步骤:
http://www.cnblogs.com/hnrainll/p/3597246.html
创建一个HandlerThread,即创建了一个包含Looper的线程

HandlerThread handlerThread = new HandlerThread("test");
handlerThread.start(); //创建HandlerThread后一定要记得start()

获取HandlerThread的Looper

Looper looper = handlerThread.getLooper();

创建Handler,通过Looper初始化

Handler handler = new Handler(looper);

通过以上三步我们就成功创建HandlerThread。通过handler发送消息,就会在子线程中执行。
如果我们在Activity的onCreate中进行上面的初始化,不再进行其他工作,那么就有可能造成内存泄漏。
因为不过Activity finish后,进程没有退出,那么创建的test会一直存在。

解决办法:
在onDestory中调用handlerThread.quit()或handlerThread.quitSafely();

Thread内存泄漏

线程也是造成内存泄漏的一个重要的源头。线程产生的内存泄漏主要原因在于线程生命周期的不可控。比如线程是Activity的内部类,则线程对象中保存了Activity的一个引用,当线程的run函数耗时较长没有结束时,线程对象是不会被销毁的,因此它引用的老的Activity也不会被销毁,因此就出现了内存泄漏的问题。

一些不良代码造成的内存压力

这些代码并不造成内存泄漏,但是它们,或是对没使用的内存没有进行有效及时的释放,或是没有有效的利用已有的对象而是频繁的申请新内存。

Bitmap没调用recycle()

Bitmap对象在不使用时,我们应该先调用recycle()释放内存,然后将它设置为null。因为加载Bitmap对象的内存空间,一部分是java的,一部分C的(因为Bitmap分配的底层是通过JNI调用的)。而这个recycle()就是针对C部分的内存释放。

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

http://blog.csdn.net/u010878994/article/details/51553415

版权声明:转载请注明出处

Android中常出现的内存泄漏情况分析

Android中常出现的内存泄漏情况分析
  • Urchin_dong
  • Urchin_dong
  • 2016年02月12日 18:38
  • 863

Android开发中常见的内存泄漏情况和解决办法

什么是内存泄漏?答:在Android程序开发中,当一个对象已经不需要再使用了,本该被回收时,而另外一个正在使用的对象持有它的引用从而导致它不能被回收,这就导致本该被回收的对象不能被回收而停留在堆内存中...
  • da_caoyuan
  • da_caoyuan
  • 2017年08月08日 17:49
  • 565

Android内存泄漏产生的6大原因

1.资源对象没关闭造成的内存泄漏 描述: 资源性对象比如(Cursor,File文件等)往往都用了一些缓冲,我们在不使用的时候,应该及时关闭它们,以便它们的缓冲及时回收内存。它们的缓冲不仅存在于 ...
  • MYBOYER
  • MYBOYER
  • 2015年02月28日 13:00
  • 1635

Android Context导致的内存泄漏分析(示例代码+分析工具使用)

Android开发中因为有限的内存,以及防止OOM问题出现,解决内存泄漏问题将是开发者一直持续下去的工作。本文就分析了不当使用(持有)context导致的内存泄漏。 1. 为什么使用Cont...
  • a369414641
  • a369414641
  • 2016年10月26日 12:08
  • 352

jianghejie/XRecyclerView内存泄漏问题

AVLoadingIndicatorView  @Override public void setVisibility(int v) { if (getVisibility() != v) ...
  • xiayu98020214
  • xiayu98020214
  • 2017年05月25日 12:00
  • 365

可能出现内存泄漏的几种情况

定义    简单来说,内存泄漏就是程序在申请一个内存空间后没有释放,直到程序运行结束后才释放。这样看起来似乎没什么大问题,但是如果程序会持续运行很长时间(例如服务器),并且可能在程每次调用某个部分的...
  • GavinGreenson
  • GavinGreenson
  • 2017年04月05日 23:04
  • 795

Android内存优化-内存泄漏的几个场景以及解决方式

一.什么是内存泄漏 在Java程序中,如果一个对象没有利用价值了,正常情况下gc是会对其进行回收的,但是此时仍然有其他引用指向这个活在堆内存中的对象,那么gc就不会认为这个对象是一个垃圾,那么就不会...
  • JKerving
  • JKerving
  • 2016年08月20日 01:14
  • 1953

Android内存泄漏产生的原因以及解决方案(OOM)

为什么会有内存泄漏? 一个不会被使用的对象,因为另一个正在使用的对象持有该对象的引用,导致它不能正常被回收,而停留在堆内存中,内存泄漏就产生了 Android系统为每个应用分配的内存是有限的,内存...
  • u012181885
  • u012181885
  • 2016年09月04日 15:48
  • 599

android-不容易发现的内存泄漏

一、Handler引起的泄漏假如程序如下方式书写:Handler mHandler = new Handler() { @Override public void han...
  • birdfly12345
  • birdfly12345
  • 2016年09月04日 21:48
  • 461

Android —— 解决MVP引起的内存泄漏

首先不了解MVP模式的孩纸先去看一下MVP再阅读本博客喽。使用MVP模式的主要作用,是它解决了业务逻辑和数据存取的紧耦合,使Presenter作为view和model的中间人,降低了数据和view的耦...
  • womengmengyan
  • womengmengyan
  • 2016年08月12日 19:11
  • 3623
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:Android导致内存泄漏的几种情形
举报原因:
原因补充:

(最多只允许输入30个字)