我想我还在尝试理解依赖注入和DI容器的作用。
如果DI意味着较低级别的组件依赖于较高级别的组件,并且没有循环引用,那么该对象是否会被垃圾收集?当我看到垃圾收集(标记和清除)时,它只保留可以使用从程序根开始的一系列引用来跟踪的对象。
由于我自己难以解释,这里有两个UML图,它们呈现了依赖注入的冲突视图,正如我所看到的那样:
DI Container注入具有所需引用的组件,并且它们每个都存储对其下一个最高命令的引用。 Main类无法访问它们,因此它们应该被垃圾收集。
DI容器为组件注入所需的引用,并保留对每个组件的引用。它们每个都存储对其下一个最高命令的引用。 Main类可以通过DI Container访问其中任何一个,因此它们不应该被垃圾收集。
答案 0 :(得分:5)
很难理解你的实际要求:
所有主流Java实现都有垃圾收集器,可以使用循环引用收集垃圾......或者更常见的是参考周期。因此,从GC的角度来看,没有特别的理由可以避免DI中的参考周期。
如果对象包含对另一个对象的引用,则只要第一个对象可以访问,就不会收集第二个对象。 DI创建的对象在这方面与其他对象没有什么不同。
明确声明的依赖关系告诉DI框架某些对象需要在其他对象之前构建和连接。他们没有说什么需要连接到什么,以及是否存在(Java级别)参考周期。
“从广义上讲,引用(对象)只有在零引用仍然存在时才有资格进行垃圾收集(例如:您无法以编程方式访问它)”
这是误导。显然,包含对自身的引用的对象具有(至少)一个引用,但如果这是唯一的现有引用,则该对象仍然有资格进行垃圾回收。
实际上,如果某个对象不能可以,则该对象符合收集条件。对于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();
}
}