Java内存泄漏与否?

时间:2014-10-25 02:34:39

标签: java memory-leaks

看来我的项目在清除之后没有正确清除某些对象。我试图找出问题所在,并想知道以下是否代表内存泄漏。 让我们说类Parent存储一个Child类型的对象。稍后,Child对象初始化Thing类的变量。 Class Thing包含对Child的引用。如果Parent然后调用clear()将Child设置为null,那么仍然会保留类Thing中对Child的引用吗?

public class Parent {
    private Child ex = new Child();

    public void clear() {
        ex = null;
    }

}

public class Child {

    private Thing thing;

    public Child() {
        thing = new Thing(this);
    }

}

public class Thing {

    private Child ex;

    public Thing(Child e) {
        ex = e;
    }

}

3 个答案:

答案 0 :(得分:3)

可以添加以下代码以使其更清晰(和正常工作):

public static void main(String[] args) {
  new Parent().clear();
}

因此,有两个保持引用的对象(至少在理论上):

    通过Thing
  • Child.thing个对象 通过Child
  • Thing.ex个对象

因为一张图片胜过千言万语(因为我真的很喜欢ASCII艺术):

parent.clear()之前的情况

parent
 -ex  ----> child <----------------+
             -thing  ----> thing   |
                            -ex  --+

parent.clear()

之后的情况
parent
 -ex        child <----------------+
             -thing  ----> thing   |
                            -ex  --+

           Two remaining objects on the 
           heap referencing each other. 


当然,引用仍然只在堆上,但The Java® Language Specification, Java SE 8 Edition中没有关于&#34; live thread&#34; &#34;静态引用&#的内容34; &#34;可访问&#34; &#34;来自某些&#39; root&#39;的明确路径(stack var,static var等)&#34; 与垃圾收集相结合。这就是我发现的搜索&#34;垃圾&#34;:

(1)Ch. 1. Introduction - &#34; Java编程语言包括自动存储管理,通常使用垃圾收集器,&#34;

通常不是必然。

(2)1.1. Organization of the Specification - &#34;当一个对象不再被引用时,它可能被垃圾回收 。集电极&#34;

可能

正如Jason C指出The Java® Virtual Machine Specification中有关于GC的内容:

(3)2.5.3. Heap - &#34;对象的堆存储由自动存储管理系统(称为垃圾收集器)回收;&#34;

(4)2.5.4: Method Area - &#34;虽然方法区域在逻辑上是堆的一部分,但简单的实现可能选择不垃圾收集它。 &#34;

结论:GC可能(并且很可能是)实现,以识别仅在堆上的对象之间存在的引用,以便删除关联的对象。但这不是JLS或JVM规范的问题。它是特定于实现的,因此无法普遍回答。


其他信息:

有一个术语&#34;可访问&#34; in:&#34; 6.6访问控制 - 如果允许访问,则访问 据说实体可以访问。&#34; →但该部分是关于AC的,而不是关于GC。

引用对象的正确术语是可到达,而&#34;活动线程&#34; 也在那里:&#34; 12.6.1实现终结 - 可访问对象是任何可以从任何活动线程继续计算中访问的对象。&#34; →但该部分是关于最终确定,而不是关于GC。

答案 1 :(得分:2)

根据所提供的信息,您的问题无法回答,因为这完全取决于是否存在对Child对象的任何其他当前引用。仅仅因为Parent使变量无效并不意味着先前引用的变量丢失了所有引用的对象。另一方面,如果您确定没有其他对Child对象(或其组成部分)的活动引用,那么Child对象可用于GC。


修改
你问,

  

我想知道Child中的类变量(包含对Child的引用)是否会在Parent类将其Child设置为null后保留引用。此示例中没有其他参考。

是的,thing变量仍将引用所创建的Thing对象,但是如果没有其他对该Thing的引用,则所有这些都可用于GC,如果Child丢失所有引用,既不是Child对象,也不是任何实时线程或静态引用都可以访问Thing组件。

答案 2 :(得分:1)

您所谈论的是与对象图的其余部分断开连接的对象周期。

Java的垃圾收集器通过遍历可从一小组根对象到达的所有对象并处理其余对象来工作。事实上,它并不关心它没有达到的东西,它可能是未引用的对象或只是随机的未初始化的内存 - 我认为这是Java中没有析构函数的因素之一。

你提到的那个问题会出现在使用引用计数进行内存管理的语言中,比如Objective-C有/有(它可能已经改变了最近的那种,我无法回想起)。由于两个对象都被另一个引用,因此free d中没有一个是可以理解的。

你可以在Ken Fox的文章Visualising Garbage Collection Algorithms中看到一些额外的解释(以及一些迷人的动画 - yay!)。