美文网首页
内存泄漏简记

内存泄漏简记

作者: 清明捉鬼 | 来源:发表于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