您的位置:首页 > 编程语言 > Java开发

第六条 消除过期的引用

2016-06-01 15:57 169 查看
java 中有自动垃圾回收机制,如果以为不用自己手动处理,jvm可以全局处理,那就有点错了

例如

 public class Stack {

private Object[] elements;

private int size = 0;

private static final int DEFAULT = 16;

public Stack(){

elements = new Object[DEFAULT];

}

public void push(Object o){

ensure();

elements[size++] = o;

}

public Object pop(){

if(size == 0){

throw new EmptyStackException();

}

return elements[--size];

}

private void ensure(){

if(elements.length == size){

elements = Arrays.copyOf(elements, size *2 +1);

}

}

}

joshua大神的例子

这段代码看起来没问题,但有个小问题:内存泄漏。随着数组笔挺变大,程序性能会下降,应为 数组 elements 不停增大,调用 pop()功能,数据仍然存在数组中,极端情况,数组会造成内存泄漏 oom。 一个类似的例子时集合,我们用到集合后,有些小伙伴会在不用时置空,以为完事,其实置空前应该先 clean()一下,清除集合里面的元素,然后吧集合对象置空。

同理,上述数组中,可以修改  pop()方法,在弹出数组对象时,把数组里面的引用置空

 public Object pop(){

if(size == 0){

throw new EmptyStackException();

}

Object obj = elements[--size];

elements[size] = null;

return obj;

}

清除过期引用的另一个好处是一旦被错误引用,程序会立刻抛出异常,而不是悄悄的继续错误的运行下去。

effective java 作者 joshua大神明确说:清空对象引用应该是一种例外,而不是一种规范行为。

是不是觉得前后矛盾? 这么说主要是因为 对于每一个程序对象,一旦不用就清空,很容易把代码弄混乱,消除过期引用的最好方法时控制其生命周期来结束引用,而不是到处置空。一般而言,只要是类自己管理内存,我们就该警惕内存泄漏了,就像是上述代码一样。

另一种是缓存。把对象引用放入缓存,很容易就被遗忘。对于这种,常见的解决方案是弱引用。缓存中的内容过期后,自动被删除。或者采用类似 LinkedHashMap 的容器,在增加新条目的同时会自动清理以前的条目,对于更复杂的封装好的缓存工具,可以使用 java.lang.ref。

第三种常见的是监听器和其他回调。如果只注册回调,没有对应的取消注册,那么就会越聚越多,造成内存泄漏。Android中常见的就是广播注册,没有在activity结束的生命周期里取消注册。

内存泄漏是一个大的模块,只有在平常中积累,才能慢慢提高。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  java 广播监听