java - 引用数组索引会造成内存泄漏吗?

标签 java memory memory-management memory-leaks garbage-collection

我正在阅读 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);
    }
}

根据此项,内存泄漏是因为在 popping 后,数组索引未被引用为 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/

相关文章:

c# - C#直接访问DirectDraw表面内存

c - Wireshark 插件导致 'heap corruption'

c - C 如何处理本地字符串文字的内存?

java - 在JAVA中使用正则表达式替换重复的字母

java - 在 Saucelabs 中使用 Selenium 远程 Firefox Webdriver 安装扩展时出现问题

caching - Redis 作为缓存和使用相同实例的队列

linux - 使用物理地址获取内存的哪种实现是正确的?

c - 如何创建已知最大大小的结构结构

java - 如何使用 javax swing 计时器的整数数组来改变速度

数组中项目的 Java 计数(类似于 SQL 聚合函数)