条款7:清除过期的对象引用
以下代码实现了一个栈:
public class Stack {
private Object[] elements;
private int size = 0;
private final static int DEFAULT_INITIAL_CAPACITY = 16;
public Stack() {
elements = new Object[DEFAULT_INITIAL_CAPACITY];
}
public void push(Object e) {
ensureCapacity();
elements[size++] = e;
}
public Object pop() {
if (size == 0) {
throw new EmptyStackException();
}
return elements[--size];
}
private void ensureCapacity() {
if (elements.length == size) {
elements = Arrays.copyOf(elements, 2 * size + 1);
}
}
}
这段代码看上去没问题,但实际上会造成内存泄漏。注意pop方法,弹出栈的元素并不会被gc回收,因为栈保存了过期的对象引用(再也不会被解引用的对象引用)。pop方法应当添加一行代码
public Object pop() {
if (size == 0) {
throw new EmptyStackException();
}
Object result = elements[--size];
elements[size] = null;
return result;
}
但是,我们也不把所有用完的对象引用都设置为null,把引用设置为null应该是例外而非规范。消除过期引用的最好方法是让每个变量都处在最小作用域中。
总的来说,当类自己管理内存时,需要警惕内存泄漏。缓存,监听器和其他回调都有可能引起内存泄漏,可以保存到WeakHashMap的Key中来确保被垃圾回收。
条款8:避免使用finalize和clean
不要用finalize和clean
不要用finalize和clean
不要用finalize和clean
条款9:用try-with-resources替代try-finally
try-finally有两个缺点:
1. 关闭资源时代码很丑很长;
2. debug时,想要的异常信息会被不想要的异常信息顶掉。
所以只要资源实现了AutoCloseable接口,那就采用try-with-resources吧!更好写更清晰,而且异常信息更加有助于debug。