【问题标题】:Garbage collector and anonymous classes垃圾收集器和匿名类
【发布时间】:2017-06-23 00:16:54
【问题描述】:

我们有代码:

Iterator<Object> it = new Collection<Object>(){/*...implementation...*/}.iterator();

问:垃圾收集器会删除我为表达收集而创建的对象吗?形式上,我们没有对这个对象的引用,但it (Iterator &lt;Object&gt;) 仍然与我们的匿名类对象的内部相连。

换句话说,考虑一下代码:

Iterator<Object> it = new Collection<Object>(){             // String (1)

    private Object[] array;

    public Iterator<Object> iterator(){
        /*Here, an iterator that references this.array is returned
        + Performing its tasks*/
    } 

    /* + other implementation...*/ 

}.iterator();

那么 GC 是否会删除第一行创建的对象,而我们客观上没有链接到该对象? //String (1)

对于那些特别喜欢编写伪答案的人,这里是我的迭代器的代码:

Iterator<Object> it = new Collection<Object>() { // String (1)

        private Object[] array2;

        @Override
        public Iterator<Object> iterator() {
            return new Iterator<Object>() {
                Object[] array;
                {
                    array = array2;
                }
                @Override
                public boolean hasNext() {
                    // We do what is necessary
                    return false;
                }
                @Override
                public Object next() {
                    // We do what is necessary
                    return null;
                }
            };
        }

        /* + other implementation... */
}.iterator();

小额外问:

我可以将 Collection 实现中的“array2”重命名为“array”吗?那么如何在Iterator的实现中使用它呢?

return new Iterator<Object>() {
    Object[] array;
    {
        array = array2;   // array = array ? It doesn't work. How refer to array above
    }
    // and so on...

关于重复...不是this question。也许看起来像,但我想收到关于删除问题的答案。这会发生还是不会发生,为什么? + 收到其他问题的答案很重要。 That question 可以帮助别人理解我的问题的答案,但不是我。

【问题讨论】:

标签: java collections garbage-collection


【解决方案1】:

如果你给它命名为array,你不能访问外部类的字段,只要外部类是一个匿名的内部类。但是,第二个array 字段的整个维护已经过时,因为它不会阻止内部(大多数)类维护对其外部实例的引用,正如Do anonymous classes always maintain a reference to their enclosing instance? 中已经解释的那样。

解决这两个问题的方法是一样的,要么不使用匿名内部类,而是使用命名嵌套类,要么将其移动到没有外部实例在范围内的工厂方法中:

    Iterator<Object> it = new AbstractCollection<Object>() {
        private Object[] array;
        @Override
        public Iterator<Object> iterator() {
            return getIterator(array);
        }
        @Override
        public int size() {
            throw new AssertionError("no-one's gonna call this here");
        }
    }.iterator();
…

static Iterator<Object> getIterator(final Object[] array) {
    return new Iterator<Object>() {
        @Override
        public boolean hasNext() {
            // We do what is necessary
            return false;
        }
        @Override
        public Object next() {
            // We do what is necessary
            return null;
        }
    };
}

当然,这仍然留下两个问题

  1. 当我们已经知道我们要做的就是调用iterator() 方法时,Collection 实现的意义何在?为什么不首先调用getIterator 方法呢?

  2. 如果我们在这一点上,为什么不直接调用Arrays.asList(array).iterator()(请记住,这复制数组)?

也就是说,拥有引用并不一定会阻止垃圾收集。考虑The Java® Language Specification, §12.6.1

可达对象是可以在任何潜在的持续计算中从任何活动线程访问的任何对象。

可以设计优化程序的转换,将可到达的对象的数量减少到比那些天真地认为是可到达的要少。例如,Java 编译器或代码生成器可能会选择将不再使用的变量或参数设置为 null,以使此类对象的存储空间可能更快地被回收。

请注意,这甚至适用于 Iterator 实例,在将其代码内联到调用者(即循环)后,其存储可能会被回收,因此它只适用于数组。但是您不会注意到这一点,因为优化器当然会确保程序的行为不会改变。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-01-06
    • 1970-01-01
    • 1970-01-01
    • 2015-03-14
    相关资源
    最近更新 更多