如何防止依赖注入和垃圾收集的循环引用?

时间:2011-05-26 01:15:14

标签: java actionscript-3 oop dependency-injection garbage-collection

我想我还在尝试理解依赖注入和DI容器的作用。

如果DI意味着较低级别的组件依赖于较高级别的组件,并且没有循环引用,那么该对象是否会被垃圾收集?当我看到垃圾收集(标记和清除)时,它只保留可以使用从程序根开始的一系列引用来跟踪的对象。

由于我自己难以解释,这里有两个UML图,它们呈现了依赖注入的冲突视图,正如我所看到的那样:

我对DI的原始解释

DI Container注入具有所需引用的组件,并且它们每个都存储对其下一个最高命令的引用。 Main类无法访问它们,因此它们应该被垃圾收集。 DI Container does NOT store references to its components

我重新考虑DI

DI容器为组件注入所需的引用,并保留对每个组件的引用。它们每个都存储对其下一个最高命令的引用。 Main类可以通过DI Container访问其中任何一个,因此它们不应该被垃圾收集。 DI Container DOES store references to its components

2 个答案:

答案 0 :(得分:5)

很难理解你的实际要求:

  • 所有主流Java实现都有垃圾收集器,可以使用循环引用收集垃圾......或者更常见的是参考周期。因此,从GC的角度来看,没有特别的理由可以避免DI中的参考周期。

  • 如果对象包含对另一个对象的引用,则只要第一个对象可以访问,就不会收集第二个对象。 DI创建的对象在这方面与其他对象没有什么不同。

  • 明确声明的依赖关系告诉DI框架某些对象需要在其他对象之前构建和连接。他们没有说什么需要连接到什么,以及是否存在(Java级别)参考周期。


<@> @ JonnyReeve的回答说:

  

“从广义上讲,引用(对象)只有在零引用仍然存在时才有资格进行垃圾收集(例如:您无法以编程方式访问它)”

这是误导。显然,包含对自身的引用的对象具有(至少)一个引用,但如果这是唯一的现有引用,则该对象仍然有资格进行垃圾回收。

实际上,如果某个对象不能可以,则该对象符合收集条件。对于Java,定义(JLS 12.6.1)如下:

  

“可访问的对象是任何可以从任何活动线程继续计算中访问的对象。”

请注意谨慎行事。这意味着一个对象可以被垃圾收集,而局部变量仍然引用它...只要JVM可以告诉未来的计算不会访问该对象。

答案 1 :(得分:1)

AVM中的垃圾收集是一个非常大的主题;我建议你先阅读格兰特斯金纳关于Resource Management的文章,而不是试图超越这里的细节。

回答有关参考文献的问题;一般来说,引用(对象)只有在零引用仍然存在时才有资格进行垃圾收集(例如:您无法以编程方式访问它);通常只需将引用归零即可实现;例如:

public class Client {
    private var myFoo : Foo;

    public function Client() {
        // myFoo will count as a reference; it will not be 'swept'
        myFoo = new Foo();

        // Business as usual.
        myFoo.bar();
    }

    public function destroy() : void {
        // Remove the reference to myFoo, it can now be 'swept' as no other
        // references remain to it and there is no way to access it.
        myFoo = null;

        // This will trip a Null Reference Error because myFoo is no longer a
        // reference to the 'Foo' instance.
        myFoo.bar();
    }
}
相关问题