OnDestroy()里的一些思考。----不使用的对象应手动赋值为null 的正确理解姿势

Posted callMeVita

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了OnDestroy()里的一些思考。----不使用的对象应手动赋值为null 的正确理解姿势相关的知识,希望对你有一定的参考价值。

@[email protected]导火索来自于app启动页的 onDestroy里的 mImage=null;这一句。

起初我在思考为什么要把成员变量设为null呢?难道destroy不会清除掉mImage吗?

崇拜一下健哥。持有imageview对象的理解焕然一新。

拿Activity举例,fragment,view啊都适用。

在一个Activity中,通过布局,Activity会持有ImageView的对象。我们通过findviewbyid去获取ImageView对象的引用,如上面提到的mImage。而ImageView对象通过Glide或者别的图片加载框架与底层中图片(bitmap)形成持有关系。ImageView这个对象在堆中占有内存非常小,而bitmap往往非常大,十几m或者几十m,与屏幕大小以及清晰度有关。所以app需要及时清除掉不用的bitmap,我们可以断开bitmap与ImageView对象的持有关系。有两种思路,1:断开bitmap与ImageView对象的持有关系。项目里常常用到的releaseBitmap(),核心方法

Glide.clear(view);

。这个方法有一个好处就是,ImageView对象仍在,当需要重新加载bitmap的时候会非常的快,省去了创建ImageVierw的过程。

2,把ImageView对象与Bitmap一起remove掉。有的时候ImageView的对象的生命周期非常长,ImageView不被释放掉,可我们也不需要它,我们就remove这个对象。这个时候你有没有想到上文提到的mImage=null呢?如果你想到了,恭喜你,想错了。mImage只是ImageView对象的引用,mImage=null了并不影响Activity对ImageView对象的持有,要断开Activity对ImageView对象的持有就不像别的地方(如mData=null,可以断开对mData指向的对象持有关系,如果mData没有别的引用关系,mData就会被GC回收掉)处理方式。正确姿势是:

((ViewGroup) mRoot.getParent()).removeView(mRoot);

mRoot可以换成mImage。将ImageView与Bitmap都remove掉。所以mImage=null,好像真的有点多余,不知道之前程序员小哥哥为什么写这一句,也不太敢删。

 

@[email protected]在OnDestroy里。handler可能导致内存泄漏。(待填坑)

@[email protected]在OnDestroy里。网络请求是否取消问题,衍生异步回调引发的空指针问题。

(待填坑)

 

 

 

 

 

补充一下,之前为了了解mImage=null,我特地查了一下 ,相关有一篇这个文章:

Java: 对象不再使用时赋值为null的作用和原理

讲的没错,举例有点过犹不及。在一个调用一个方法的时候,一个线程对应一个Java栈,栈中会存储局部变量。

public static void main(String[] args) {
    if (true) {
        byte[] placeHolder = new byte[64 * 1024 * 1024];
        System.out.println(placeHolder.length / 1024);
    }
    System.gc();
}

当方法没执行完,在局部变量的作用域之外,placeHolder这个引用变成了空指针,但是new byte[64 * 1024 * 1024]这个对象仍可能存在,它的实际地址值(if里placeHolder被赋的值)也就是这个对象在内存中的地址还是保存在栈里面的,gc就无法把它给回收掉。

public static void main(String[] args) {
    if (true) {
        byte[] placeHolder = new byte[64 * 1024 * 1024];
        System.out.println(placeHolder.length / 1024);
        placeHolder = null;
    }
    System.gc();
}

public static void main(String[] args) {
    if (true) {
        byte[] placeHolder = new byte[64 * 1024 * 1024];
        System.out.println(placeHolder.length / 1024);
    }
    int replacer = 1;
    System.gc();
}

gc可以马上回收掉new byte[64 * 1024 * 1024]对象。当在placeHolder 作用域范围内手动赋值null,就断开了引用和对象间的联系,对象如果没有被别的地方引用,就会被孤立于GC算法的引用表之外,GC就会回收它。如果在作用域外部,栈内添加局部变量,由于栈会自己检测超出作用域的引用的对象,然后remove该对象的栈中的地址,腾出空间保存新对象的地址,所以原来对象也会被GC。

这样做的意义?这篇文章为了阐明这个观点引用了不太合适的例子。倘若System.gc()在方法以外,那么结果会相同,new byte[64 * 1024 * 1024]对象都会被GC掉。因为Java栈都被清空了;手动赋值null使之GC,比方法执行完系统GC的结果可能就是提前几十毫秒。所以赋值为null要视情况而定,考虑方法生命周期,变量生命周期与使用时间。

 

以上是关于OnDestroy()里的一些思考。----不使用的对象应手动赋值为null 的正确理解姿势的主要内容,如果未能解决你的问题,请参考以下文章

关于面向对象的一些思考

不对称加密世界里的对称思考

service的简单使用

混合方式开启服务

关于《后浪》的一些思考(5.5的草稿,忘发了)

onDestroy() onTaskRemoved 两者都不能在 Redmi MI 设备上运行