Java 如何通过依赖项注入和垃圾回收防止循环引用?

Java 如何通过依赖项注入和垃圾回收防止循环引用?,java,actionscript-3,oop,dependency-injection,garbage-collection,Java,Actionscript 3,Oop,Dependency Injection,Garbage Collection,我想我仍在努力理解依赖注入和DI容器的作用 如果DI意味着较低级别的组件依赖于较高级别的组件,并且没有循环引用,那么该对象不会被垃圾收集吗?正如我看到的垃圾收集(mark和sweep),它只保留可以通过从程序根开始的引用链进行跟踪的对象 因为我很难解释自己,这里有两个UML图,在我看来,它们呈现了相互冲突的依赖注入视图: 我对DI的最初解释 DI容器使用组件所需的引用注入组件,每个组件都存储对其下一个最高级别命令的引用。主类无法到达它们,因此它们应该被垃圾收集。 我对DI的反思 DI容器使用组

我想我仍在努力理解依赖注入和DI容器的作用

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

因为我很难解释自己,这里有两个UML图,在我看来,它们呈现了相互冲突的依赖注入视图:

我对DI的最初解释 DI容器使用组件所需的引用注入组件,每个组件都存储对其下一个最高级别命令的引用。主类无法到达它们,因此它们应该被垃圾收集。

我对DI的反思 DI容器使用组件所需的引用注入组件,并维护对每个组件的引用。它们各自存储对下一个最高命令的引用。主类可以通过DI容器访问它们中的任何一个,因此它们不应该被垃圾收集。
很难理解你到底在问什么:

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

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

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


@JonnyReeve的回答是这样的:

广义地说,引用(对象)只有在保留零引用时才有资格进行垃圾收集(例如:您无法以编程方式访问它)

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

事实上,如果对象不可访问,则该对象符合收集条件。对于Java,定义如下(JLS 12.6.1):

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


请注意措辞的谨慎方式。这意味着一个对象可以被垃圾收集,而局部变量仍然引用它。。。前提是JVM可以判断未来的计算不会访问该对象。

很难理解您的实际要求:

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

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

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


@JonnyReeve的回答是这样的:

广义地说,引用(对象)只有在保留零引用时才有资格进行垃圾收集(例如:您无法以编程方式访问它)

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

事实上,如果对象不可访问,则该对象符合收集条件。对于Java,定义如下(JLS 12.6.1):

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


请注意措辞的谨慎方式。这意味着一个对象可以被垃圾收集,而局部变量仍然引用它。。。前提是JVM可以判断未来的计算不会访问该对象。

AVM中的垃圾收集是一个相当大的主题;我建议你从阅读格兰特·斯金纳的文章开始,而不是试图在这里讨论更细微的问题

回答你关于推荐人的问题;广义地说,一个引用(对象)只有在零引用仍然存在的情况下才有资格进行垃圾收集(例如:您无法以编程方式访问它);通常,这是通过简单地取消一个引用来实现的;例如:

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();
    }
}

AVM中的垃圾收集是一个相当大的主题;我建议你从阅读格兰特·斯金纳的文章开始,而不是试图在这里讨论更细微的问题

回答你关于推荐人的问题;广义地说,一个引用(对象)只有在零引用仍然存在的情况下才有资格进行垃圾收集(例如:您无法以编程方式访问它);通常,这是通过简单地取消一个引用来实现的;例如:

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();
    }
}

不幸的是,第二段不准确;见我的最新答案。不幸的是,第二段不准确;请参阅我的最新答案。