如何垃圾收集已创建其内部类实例的对象?

时间:2012-01-11 01:42:55

标签: java

Java垃圾收集器无法在我编写的程序中收集死对象,我相信这是因为死对象已经创建了内部类的实例。

当我在调试模式下查看内部类的实例时,应该在收集创建者之后,找到一个标题为this$0的引用,它指向应该死的对象。

有没有办法阻止在Outer.this的每个实例中由java创建Inner引用?该字段在程序中没有用处,它所做的只是防止垃圾收集,很快导致堆耗尽内存。从Inner移出Outer不是一种选择,因为它有public个数据字段,只有Outer可见。

3 个答案:

答案 0 :(得分:4)

您的内部类维护this$0,以便它可以获取外部类的私有字段和方法。如果内部类不需要在外部类中使用任何内容,则可以标记内部类static以防止它维护对包含类的实例的引用。

答案 1 :(得分:4)

  

尽管如此,我需要我的内部类是非静态的,因为它的每个实例都需要调用使用它的非静态实例数据的非静态方法。

在这种情况下,外部对象不应该被垃圾收集...因为外部对象是实例数据所在的位置!


<强>后续

  

那么你会推荐什么?我不知道如何使用包,但我需要创建Inner的实例,这些实例只有Outer可访问的公共数据字段,并且可以在Outer的销毁之后存活下来。我运气不好吗?

在我回答你的问题之前:

  • “我不知道如何使用包裹......” - 那么你应该了解它们。包和“包私有”访问是Java语言的重要组成部分。

现在问你的问题......

如果只希望Outer类(以及嵌套在其中的类)可以访问字段,那么必须使用嵌套或内部类。 (如果您尝试使用包和包私有访问来执行此操作,那么在同一个包中声明的其他类也可以访问这些字段。但是,如果这是可接受的,那么包是一种更简单的方法。)

假设您要使用嵌套或内部类来执行此操作,则有两种方法可以执行此操作:

  • 如果您将Inner类声明为private static class Inner,那么Inner类中的方法无法调用Outer的实例方法或访问实例字段...除非他们引用了Outer实例(例如作为参数传递)。如果Innerstatic,则InnerOuter的实例的生命周期是独立的。

  • 如果您将Inner类声明为private class Inner,那么Inner类中的方法可以调用Outer的实例方法或访问实例字段。但另一方面,Outer实例及其Inner实例的生命周期现在依赖于它。具体而言,只要至少有一个Outer实例继续存在,就会存在Inner实例。 (反之则不然......除非Outer实例在(例如)集合类型字段中保留对Inner个实例的引用。)

重述我之前所说的话。如果Inner实例需要访问Outer实例上的实例字段或调用实例方法,则需要显式或引用该Outer实例。这意味着Outer实例是可访问的,并且不是垃圾收集器删除的候选者。

另一点是Inner的实例如果仍然可以访问则不会消失;即,如果正在运行的应用程序的某些部分引用了它可能使用的实例。在Java中,如果任何可能它们可以被正在运行的应用程序使用,则不会对对象进行垃圾回收。在这方面,内部/嵌套类的实例并不特殊。


实际上,可能有一种(非常讨厌的!)方式来打破InnerOuter实例之间的联系。如果您可以找到所有Inner个实例,则可以使用反射将null分配给每个this$0隐藏变量。但是,如果这样做,Inner类中引用Outer实例状态的任何代码都将中断。如果你要采用这种肮脏的方式,最好将Inner声明为static类。

答案 2 :(得分:0)

关于你所能做的就是让内部类静态,或者根本不使用内部类。

当然,您可以使用包作用域来限制类中字段的可见性,而不必求助于内部类。