• android内存泄露-总结


    1.GC root:

    1、  Class:由系统的类加载器加载的类对象

    2、  Static Fields

    3、  Thread:活着的线程

    4、  Stack Local: java方法的局部变量或参数

    5、  JNI Local: JNI方法中的局部引用

    6、  JNI Global: 全局的JNI引用

    7、  Monitor used: 用于同步的监控对象

    8、Help by VM: 用于JVM特殊目的由GC保留的对象

     

     

     

     

     

     

     

     

    每个应用最大可使用的堆内存受到Android系统的限制:getMemoryClass()

    2.context内存泄露

     1、如果一个类持有Context对象的强引用,就需要检查其生存周期是否比Context对象更长。否则就可能发生Context泄漏。

     2、View持有其创建所在Context对象的引用,如果将View对象传递给其它生存周期比View所在Context更长的强引用,就可能会引起内存泄漏。

    例如View#setTag(int, Object)的内存泄漏https://code.google.com/p/android/issues/detail?id=18273

     3、把Context对象赋给static变量。

    避免Context对象泄漏Checklist

          1、检查所有持有对Context对象强引用的对象的生命周期是否超出其所持有的Context对象的生命周期。

          2、检查有没有把View传出到View所在Context之外的地方,如果有的话就需要检查生命周期。

          3、工具类中最好不要有Context成员变量,尽量在调用函数时直接通过调用参数传入。如果必须有Context成员变量时,可以考虑使用WeakReference来引用Context对象。

          4、View持有其创建所在Context对象的引用,如果将View对象传递给其它生存周期比View所在Context更长的强引用,就可能会引起内存泄漏。

          5、  检查把Context或者View对象赋给static变量的地方,看是否有Context泄漏。

          6、检查所有把View放入容器类的地方(特别是static容器类),看是否有内存泄漏。7、使用WeakHashMap也需要注意有没有value-key的引用。

          7、尽量使用ApplicationContext。

     

     

     

     

     

     

     

     

     

     

     

     

    3.handler泄露

    发送到Handler的Message实际上是加入到了主线程的消息队列等待处理,每一个Message持有其目标Handler的强引用。

    如我们通常使用的匿名内部类Handler

    Handler mHandler = new Handler() {
        @Override
        public voidhandleMessage(Message msg) {
           mImageView.setImageBitmap(mBitmap);
        }
    }

    上面是一段简单的Handler的使用。当使用内部类(包括匿名类)来创建Handler的时候,Handler对象会隐式地持有一个外部类对象(通常是一个Activity)的引用,因为View会依附着一个Activity。而Handler通常会伴随着一个耗时的后台线程(例如从网络拉取图片)一起出现,这个后台线程在任务执行完毕(例如图片下载完毕)之后,通过消息机制通知Handler,然后Handler把图片更新到界面。然而,如果用户在网络请求过程中关闭了Activity,正常情况下,Activity不再被使用,它就有可能在GC检查时被回收掉,但由于这时线程尚未执行完,而该线程持有Handler的引用(不然它怎么发消息给Handler?),这个Handler又持有Activity的引用,就导致该Activity无法被回收(即内存泄露),直到网络请求结束(例如图片下载完毕)。另外,如果你执行了Handler的postDelayed()方法,该方法会将你的Handler装入一个Message,并把这条Message推到MessageQueue中,那么在你设定的delay到达之前,会有一条MessageQueue -> Message -> Handler -> Activity的链,导致你的Activity被持有引用而无法被回收。

    当然,应为是Handler对外部持有引用的原因,我们就可以将Activity设置为一个弱引用,在不必要的时候,不再执行内部方法。

    publicclass WeakRefHandler extends Handler
    {
        WeakReference<Context> mWeakContext;
     
        public WeakRefHandler(Context context)
        {
            mWeakContext = newWeakReference<Context>(context);
        }
     
        @Override
        public void handleMessage(Message msg)
        {
            if((mWeakContext.get() instanceofActivity )&& ((Activity)mWeakContext.get()).isFinishing())
                    return ;
            if(mWeakContext==null){
                return ;
            }
            super.handleMessage(msg);
        }
    }

     

     

     

  • 相关阅读:
    C++ 获取图片文件信息
    java中redis的分布式锁工具类
    java中的redis工具类
    mysql中的sql查询优化
    利用Linux中的crontab实现分布式项目定时任务
    MYSQL的REPLACE和ON DUPLICATE KEY UPDATE使用
    redis学习三,Redis主从复制和哨兵模式
    redis学习五,redis集群搭建及添加主从节点
    String 转化成java.sql.Date和java.sql.Time
    SpringMVC配置双数据源,一个java项目同时连接两个数据库
  • 原文地址:https://www.cnblogs.com/zhengtu2015/p/4901106.html
Copyright © 2020-2023  润新知