【问题标题】:How to prevent Circular References with Dependency Injection and Garbage Collection?如何通过依赖注入和垃圾收集来防止循环引用?
【发布时间】:2011-05-26 01:15:14
【问题描述】:

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

如果 DI 意味着较低级别的组件依赖于较高级别的组件,并且没有循环引用,那么该对象不会被垃圾回收吗?正如我所看到的垃圾收集(标记和清除),它只保留可以通过从程序根开始的引用链跟踪的对象。

由于我难以解释自己,这里有两个 UML 图,在我看来,它们呈现了相互矛盾的依赖注入视图:

我对 DI 的原始解读

DI 容器注入组件及其所需的引用,并且它们每个都存储对其下一个最高命令的引用。 Main 类无法访问它们,因此应该对它们进行垃圾收集。

我对 DI 的重新考虑

DI Container 注入组件及其所需的引用,并维护对每个组件的引用。他们每个人都存储了对其下一个最高指挥官的引用。 Main 类可以通过 DI Container 访问它们中的任何一个,因此它们不应该被垃圾收集。

【问题讨论】:

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


    【解决方案1】:

    很难理解你实际上在问什么:

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

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

    • 显式声明的依赖项告诉 DI 框架某些对象需要先于其他对象构建和连接。他们没有说明什么需要连接到什么,以及是否存在(Java 级别)引用循环。


    @JonnyReeve 的回答是这样的:

    “一般来说,一个引用(对象)只有在零引用仍然存在时才有资格进行垃圾回收(例如:您无法以编程方式访问它)”

    这是误导。显然,包含对其自身的引用的对象(至少)还剩下一个引用,但如果这是唯一存在的引用,那么该对象仍然可以进行垃圾回收。

    事实上,如果一个对象可达,它就有资格被收集。对于 Java,其定义(JLS 12.6.1)如下:

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

    注意措辞的谨慎方式。这意味着当局部变量仍然引用它时,可以对对象进行垃圾回收……前提是 JVM 可以判断未来的计算将不会访问该对象。

    【讨论】:

      【解决方案2】:

      AVM 中的垃圾收集是一个相当大的主题;我建议您先阅读 Grant Skinner 在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();
          }
      }
      

      【讨论】:

      • 很遗憾,第二段不准确;查看我的更新答案。
      猜你喜欢
      • 2012-12-26
      • 1970-01-01
      • 1970-01-01
      • 2016-05-31
      • 1970-01-01
      • 1970-01-01
      • 2011-12-20
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多