示例:
你找的出来下面代码中的内存泄漏(memory leak)吗
public class Stack {
private Object[] elements;
private int size = 0;
private static final int DEFAULT_ININTIAL_CAPACITY = 16;
public Stack() {
elements = new Object[DEFAULT_ININTIAL_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出来的对象将不会被当做垃圾回收.
即使使用栈的程序不在引用这些对象,他们也不会被回收.
因为栈内部维护这这些对象的过期引用(永远不会再被解除的引用)
上面代码中,pop方法:
public Object pop() {
if (size == 0) {
throw new EmptyStackException();
}
return elements[--size];
}
这里将一个元素弹出后,引用仍被栈内部保存着,所以需要手动将其消除:
public pop() {
if (size == 0) {
throw new EmptyStackException();
}
Object result = elements[--size];
elements[size] = null; // Eliminate obsolete reference.
return result;
}
清除过期引用好处:
- 避免内存泄漏
- 避免错误处理引用, 会抛出NullPointException,而不是悄悄的继续运行,导致查不出bug.
清空对象引用应该是一种例外,而不是一种规范行为
消除过期引用的最好的方法:让包含该引用的变量结束在其生命周期.
Stack类自己管理内存.
一般而言,只要类是自己管理内存,程序员就应该警惕内存泄漏问题.一旦元素被释放掉,则该元素中包含的任何对象引用都应该被清空.
内存泄漏的另一个常见来源是缓存. 应该时不时清除缓存中没有用的项.(LinkedHashMap)
内存泄漏的第三个常见来源:监听器和其他回调. (只注册,未注销)
内存泄漏常见来源:
- 过期引用
- 缓存
- 监听器和其他回调