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性能优化(一)内存泄露优化(静态变量、单例模式、属性动画)

内存泄露优化分为两个方面,一方面是在开发过程中避免写出有内存泄露的代码,另一方面是通过一些分析工具比如 MAT来找出潜在的内存泄露继而解决。 一、静态变量导致内存泄露。一般情况下静态变量引用了或者内部...

android 内存泄漏案例解析

Android 编程所使用的 Java 是一门使用垃圾收集器(GC, garbage collection)来自动管理内存的语言,它使得我们不再需要手动调用代码来进行内存回收。那么它是如何判断的呢?简...

Android 内存泄漏总结(超级实用)

Android 内存泄漏总结内存管理的目的就是让我们在开发中怎么有效的避免我们的应用出现内存泄漏的问题。内存泄漏大家都不陌生了,简单粗俗的讲,就是该被释放的对象没有释放,一直被某个或某些实例所持有却不...

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

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

Android 内存泄漏情形及解决办法汇总

内存泄漏对于从事Android开发的人员都不陌生,而且也很头疼,本篇博文讲带领大家走进内存泄漏的王国,体会一下它的奥秘你将了解 什么叫内存泄漏 Java内存分配策略是怎样的 一、内存泄漏定义该释放的没...
  • Tomasyb
  • Tomasyb
  • 2017年06月21日 18:55
  • 144

java内存泄漏的若干情形

用java编写的程序存在内存泄露吗? 大家可能认为JVM(java虚拟机)有良好的垃圾回收机制(GC), 不想C/C++那样需要手动回收内存。然而事实是,JVM也是基于一些算法来进行的,在满足一定条件...

Android —— 内存泄漏的几种可能

上篇博文我们讲了如何查找到内存溢出的位置,或者应用是否产生了内存溢出,由于博文长度够长了哈,我们开天辟地新开一篇博文,来讲一下发生内存泄漏的几种常见的可能情况吧。 参考文章如果持有对象的强引用,垃圾...

Android 常见的几种内存泄漏 - Handler

Handler的使用造成的内存泄漏问题应该说最为常见了,平时在处理网络任务或者封装一些请求回调等api都应该会借助Handler来处理,对于Handler的使用代码编写一不规范即有可能造成内存泄漏,如...

Android内存泄漏的几种可能

 Java是垃圾回收语言的一种,其优点是开发者无需特意管理内存分配,降低了应用由于局部故障(segmentation fault)导致崩溃,同时防止未释放的内存把堆栈(heap)挤爆的可能,所以...

Android的内存机制和常见泄漏情形

一、 Android的内存机制  Android的程序由Java语言编写,所以Android的内存管理与Java的内存管理相似。程序员通过new为对象分配内存,所有对象在java堆内分配空间;然...
  • gl_ding
  • gl_ding
  • 2015年09月03日 08:45
  • 231
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:Android导致内存泄漏的几种情形
举报原因:
原因补充:

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