我正在阅读 Effective Java 第二版的“第 6 条:消除过时的对象引用”。
下面是代码片段。
//Can you spot the "memory leak"?
public class Stack {
private Object[] elements;
private int size = 0;
private static final 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];
}
/**
* Ensure space for at least one more element, roughly doubling the capacity
* each time the array needs to grow.
*/
private void ensureCapacity() {
if (elements.length == size)
elements = Arrays.copyOf(elements, 2 * size + 1);
}
}
根据此项,内存泄漏是因为在 pop
ping 后,数组索引未被引用为 NULL,如下所示:
public Object pop() {
if (size == 0)
throw new EmptyStackException();
Object result = elements[--size];
elements[size] = null; // Eliminate obsolete reference
return result;
}
我的理解是假设对于一个给定的数组,我已经完成了 elements[0] = new Object()
然后我再次这样做 elements[0] = new Object( )
那么我的第一个对象将有资格进行垃圾回收,因为我的数组的第 0 个索引不再指向它。
我的理解有误吗?如果它是正确的,那么它是如何在 Effective Java 中显示为内存泄漏的。
最佳答案
你得到了大部分。
如果你这样做:
elements[0] = someOtherObject;
然后存储在索引 0 处的 other 元素不再被引用并且可能被收集。
但第一个 pop()
实现保留该引用 - 它只会减少存储元素的“计数器”。因此,该对象仍然被引用 - 并且不会被收集直到一个新对象被添加到堆栈中!
正如 pop()
的第二个版本中的注释明确指出的那样 - 引用必须被消除以确保堆栈不保留对该引用的引用非常反对。该对象应该被弹出 - 因此堆栈不应该保留有关该已删除对象的信息!
并确认提交:是的,当一个人推送 n 个对象,然后推送 n 个其他对象时,您就不会发生内存泄漏 - 因为底层数组引用将全部更新并指向新对象。是的,如果少于 n 个对象在弹出后被推送,陈旧的引用将被保留并防止此处的垃圾收集。
关于java - 引用数组索引会造成内存泄漏吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49116920/