Effective Java之消除过期的引用(六)

来源:互联网 发布:淘宝实名认证重新激活 编辑:程序博客网 时间:2024/05/21 08:55

容易出现内存泄漏问题的情景:

1.自己管理内存的类。

书中举出了一个内存泄漏的stack例子

class Stack{public Object[] elements;//原文为private,但这里改为public为了测试下面代码public int size=0;public Stack(int initialCapacity){this.elements=new Object[initialCapacity];}public void push(Object e){ensureCapacity();elements[size++]=e;}public Object pop() throws Exception{if(size==0)throw new Exception();return elements[--size];}private void ensureCapacity(){if(elements.length==size){Object[] oldElements=elements;elements=new Object[2*elements.length+1];System.arraycopy(oldElements,0,elements,0,size);}}}

看了代码,我们很容易发现,这个stack很容易发生内存泄漏,原因很简单,pop出来的那个元素并没有设成null,仍然有引用指向它,所以并没有被回收。

有了这个例子,我们就可以知道,容易发生内存泄漏的情况是:
类自己管理内存,类中的元素需要释放时,没有做释放的工作。所以只要是类自己管理内存都要小心翼翼。

2.缓存

为了加快访问速度,常用的方法是进行缓存,但是开发者很多时候会忘了缓存的存在,不及时释放,时间一长就会出现内存泄漏,所有需要进行及时清理,这里可以额外的线程,如Timer或者ScheduledThreadPoolExcutor解决。

3.监听器和其他回调

例子:

public class MainActivity extends AppCompatActivity implements OnNetworkChangedListener {    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        NetworkManager.getInstance().registerListener(this);    }    @Override    public void onNetworkUp() {    }    @Override    public void onNetworkDown() {    }}

AppCompatActivity实现一个接口OnNetworkChangedListener,用来监听网络的变化。然后,把这个监听器注册到NetworkManager实例中。
NetworkManager实例持有监听器(MainActivity是实现者,指向MainActivity对象的引用)。
当NetworkManger实例的生命周期比MainActivity长,当MainActivity销毁时(比如屏幕发生旋转),NetworkManager实例还没有销毁,它持有指向MainActivity对象的引用。系统回调MainActivity的onDestroy方法,这时,GC是要回收MainActivity对象的,但是,MainActivity对象依然可达(NetworkManager实例持有指向MainActivity对象的引用),所以没有回收,MainActivity对象泄露。

简单来说,对象销毁时,如果它依然被监听,那么GC无法回收

阅读全文
0 0