• Android内存泄漏总结


    内存泄漏问题老生常谈,很常见也很难根治,今天我在这里总结一下内存泄漏的原因和解决方法:

    所谓内存泄漏,就是本该被回收的对象,由于某些原因不能被回收,继续占用堆内存的这种状态,导致的结果也是显而易见的,会占用我们本可以使用的内存空间,当超出允许的内存时会引起OOM崩溃。

    导致内存泄漏的原因大致分为:

    1. 集合类
    2. static修饰的成员变量
    3. 资源对象使用后未被关闭
    4. 非静态内部类/匿名类

    1.集合类引起的内存泄漏:

    当一个对象添加至集合中的时候,该对象会被集合引用到,当想要释放的时候不能释放,只有在集合被销毁的时候该对象才可以被释放

    1 // 通过 循环申请Object 对象 & 将申请的对象逐个放入到集合List
    2 List<Object> objectList = new ArrayList<>();        
    3        for (int i = 0; i < 10; i++) {
    4             Object o = new Object();
    5             objectList.add(o);
    6             o = null;
    7         }
    8 // 虽释放了集合元素引用的本身:o=null)
    9 // 但集合List 仍然引用该对象,故垃圾回收器GC 依然不可回收该对象

    解决方法:

    因为是集合把对象引用了,那只需要吧集合释放掉集合对元素的引用也会被释放

    //释放集合
    objectList .clear(); objectList
    = null;

    2.static修饰的成员变量:

    因为被static修饰的成员变量生命周期 = 应用程序的生命周期,会在类被创建的时候加载到内存

    static静态成员变量的生命周期>该类的生命周期导致该类没法释放

    public class SecondActivity extends Activity{  
        private Handler mHandler = new Handler(){  
            @Override  
            public void handleMessage(Message msg) {  
                super.handleMessage(msg);  
                SecondActivity.this.finish();  
                this.removeMessages(0);  
            }  
        };  
      
        private static Haha haha;  
        @Override  
        protected void onCreate(Bundle savedInstanceState) {  
            super.onCreate(savedInstanceState);  
            haha = new Haha();  
            mHandler.sendEmptyMessageDelayed(0,2000);  
        }  
      
        class Haha{  
      
        }  
    }  

    像上面这种情况SecondActivity是无法被释放掉的,只有把该静态成员变量置为null,这时就不会导致内存泄漏

    protected void onDestroy() {  
        super.onDestroy();  
        if(haha!=null){  
            haha = null;  
        }  
    }  

    更常见的问题是在我们使用单例模式的时候:

    public class LeakSingleInstance {
    
        private static LeakSingleInstance mInstance;
        private Context mContext;
        
        private LeakSingleInstance(Context mContext){
            this.mContext = mContext;
        }
        public static LeakSingleInstance getInstance(Context mContext) {
            if(mInstance == null) {
                mInstance = new LeakSingleInstance(mContext);
            }
            return mInstance;
        }
    }

    这个在创建的时候AndroidStudio就提示有内存泄漏了,原因显而易见的,我们的单例模式的类是长期存在的,生命周期 = 应用生命周期,我们如果传入了上下文会导致该上下文长期被持有,不被释放,导致内存泄漏

    解决方法可以使用:

    mContext.getApplicationContext()

    直接获取ApplicationContext的上下文使用,但是ApplicationContext使用是有局限性的,使用的时候要注意。

    3.资源对象使用后未被关闭

    对于资源的使用(如 广播BraodcastReceiver、文件流File、数据库游标Cursor、图片资源Bitmap等),若在Activity销毁时无及时关闭 / 注销这些资源,则这些资源将不会被回收,从而造成内存泄漏

    // 对于 广播BraodcastReceiver:注销注册
    unregisterReceiver()
    
    // 对于 文件流File:关闭流
    InputStream / OutputStream.close()
    
    // 对于 数据库游标cursor:使用后关闭游标
    cursor.close()
    
    // 对于 图片资源Bitmap:Android分配给图片的内存只有8M,若1个Bitmap对象占内存较多,当它不再被使用时,应调用recycle()回收此对象的像素所占用的内存;最后再赋为null 
    Bitmap.recycle();
    Bitmap = null;
    
    // 对于动画(属性动画)
    // 将动画设置成无限循环播放repeatCount = “infinite”后
    // 在Activity退出时记得停止动画

    还有非静态内部类和匿名类引起的泄漏,留在下篇再分析

     by:Jungle张轶

  • 相关阅读:
    【android】 判断文件是否存在,ImageView scaletype
    【live】回老家,那些感触
    【android】 浏览文件,如浏览sd卡下的图片文件
    【android】java.lang.NoClassDefFoundError或classnotfount等异常错误
    【android】style和theme
    【android】两个按钮的宽度各占屏幕的一半
    【java】html解析
    关于敏感词过滤的一点想法
    JAVA中Vector与ArrayList异同
    MySQL实用语句 GROUP BY ... HAVING ...
  • 原文地址:https://www.cnblogs.com/widgetbox/p/8961307.html
Copyright © 2020-2023  润新知