美文网首页
内存泄漏简记

内存泄漏简记

作者: 清明捉鬼 | 来源:发表于2018-03-19 15:09 被阅读11次
    前言

    经常有人将内存泄漏内存溢出做区别,其实也是有道理的,毕竟不知道的人根本不知道这两者是啥,又都有“内存”呵呵呵(这里不要光他两比而忘记了内存抖动)。
    Android泄漏其实需要结合一张图来看,Java判断对象是否可以回收使用的而是可达性分析算法。
    在主流的商用程序语言中(Java和C#),都是使用可达性分析算法判断对象是否存活的。这个算法的基本思路就是通过一系列名为"GC Roots"的对象作为起始点,从这些节点开始向下搜索,搜索所走过的路径称为引用链(Reference Chain),当一个对象到GC Roots没有任何引用链相连时,则证明此对象是不可用的,下图对象object5, object6, object7虽然有互相判断,但它们到GC Roots是不可达的,所以它们将会判定为是可回收对象。

    图片.png

    在Java语言里,可作为GC Roots对象的包括如下几种:
    a.虚拟机栈(栈桢中的本地变量表)中的引用的对象
    b.方法区中的类静态属性引用的对象
    c.方法区中的常量引用的对象
    d.本地方法栈中JNI的引用的对象

    导致泄漏的有:
    • 单例导致内存泄露 (这个还真的必须泄漏)
    • 静态变量导致内存泄露 (基本上静态都这样)
    • 非静态内部类导致内存泄露
    • 未取消注册或回调导致内存泄露
    • Timer和TimerTask导致内存泄露
    • 集合中的对象未清理造成内存泄露
    • 资源未关闭或释放导致内存泄露
      BroadCastReceiver、Cursor、Bitmap、IO流、自定义属性attribute attr.recycle()回收。
    • 动画造成内存泄露
      轮播图就很典型
    • Context导致的泄漏
      经常我们会传Context给某个工具类,这个Context其实只有Service、Application与Activity有,但是Activity继承跟其它两个有点不一样,它继承的是子类,如下图
      QQ截图20180319150011.png
      回到话题上来,我这个Activity的Context被人所持有,那么我这个Activity肯定无法销毁,从使用上我们可以看出,这个玩意儿跟对象的实例差不多,所以我们如下写法就好了:
    public static void showToast(Context context,String content) {
            if (toast == null) {
                toast = Toast.makeText(context.getApplicationContext(),content,Toast.LENGTH_SHORT);
            } else {
                toast.setText(content);
            }
            toast.show();
        }
    

    不管是匿名内部类还是“有名”内部类,如果其直接使用外部类任何变量的话,将会持有外部类引用,这样就可能导致外部类无法销毁,譬如回调方法

    //A类中
    final TextView tvA=find.....
    B.getInstance().setOnClickListener(new onClickListener{
      @overide
    public viod onClick(){
          tvA.setText("xxx")
    }
    })
    //B类中
    public class B{
    private static final B instance;
    private onClickListener listener;
    public static B getInstance(){
    if(instance==null){
      instance=new B();
    }
    return intance;
    }
    
    private viod doXXX(){
            if(listener!=null){
                onClick();
            }
        }
    
    public interface onClickListener{
      void onClick();
    }
    public viod setOnClickListener(onClickListener listener){
       this.listener=listener;
    }
    }
    
    

    如果B类无法销毁或者B类无法短时间销毁导致A错过销毁,则销毁A的代码执行后无效果,进而导致内存泄漏

    • 监听未移除
      譬如:不需要用的监听未移除会发生内存泄露
    //add监听,放到集合里面
    tv.getViewTreeObserver().addOnWindowFocusChangeListener(new ViewTreeObserver.OnWindowFocusChangeListener() {
        @Override
        public void onWindowFocusChanged(boolean b) {
            //监听view的加载,view加载出来的时候,计算他的宽高等。
     
            //计算完后,一定要移除这个监听
        tv.getViewTreeObserver().removeOnWindowFocusChangeListener(this);
        }
    });
    /***/
    SensorManager sensorManager = getSystemService(SENSOR_SERVICE);
            Sensor sensor = sensorManager.getDefaultSensor(Sensor.TYPE_ALL);
            sensorManager.registerListener(this,sensor,SensorManager.SENSOR_DELAY_FASTEST);
            //不需要用的时候记得移除监听
            sensorManager.unregisterListener(listener);
    

    相关文章

      网友评论

          本文标题:内存泄漏简记

          本文链接:https://www.haomeiwen.com/subject/fxehfftx.html