第6条:消除过期的对象引用
Java语言相较于C与C++一个非常大的区别便是具有自动垃圾回收的功能。而这有时会给我们一个错觉,那就是不需要再考虑内存管理这方面的事情了,这种看法明显是错误的,比如下面这段代码:
public class Stack {
private Object elements[] elements;
private int size = 0;
public Object pop(){
if(size == 0){
throw new EmptyStackException();
}
return elements[--size];
}
.........
}
这段代码中并没有错误,但是不严格的讲,隐藏着一个内存泄漏的问题,这会对性能造成一定的影响,在极端情况下,甚至会导致程序崩溃(OutOfMemory错误)。
在这段代码的pop方法中,被弹出的对象不再被程序使用,但是也不会被垃圾回收,因为这个栈仍然持有着这些对象的引用。
这种现象可能会导致连锁反应,因为这个过期的对象可能又持有其他的对象,这会导致大量过期对象无法被回收。
pop方法的修正版如下:
public Object pop(){
if(size == 0){
throw new EmptyStackException();
}
Object result = elements[--size];
elements[size] = null;
return result;
}
将弹出的对象置为null,不仅可以避免内存泄漏,而且如果之后过期对象又被错误引用,就会抛出NullPointerException异常,这能在错误出现时帮助我们尽快的找到问题所在。
但是对于每一个对象引用都去手动清空的做法并没有什么必要,因为这种做法会使代码更加混乱。更好的做法应该是合理的定义每一个变量的作用域,使变量能够自然的结束其生命周期。
内存泄露的常见来源:
1.缓存
在程序编写时,很容易遗忘掉已经过期的缓存,在部分情况下,可以通过弱引用的方式来避免。
2.监听器与其他回调
如果当监听器已经无用,却没有取消注册,那么也会造成内存泄漏,这也可以通过弱引用的方式来避免。