hibernate的一对多,多对多映射等会不会引起内存的无法释放

如我有一颗自引用的树,简单的结构如:id,parentID,name,path这样






















java代码pojo

package cn;

import java.util.HashSet;
import java.util.Set;

public class Testtree implements java.io.Serializable
{

// Fields

private Long id;
private Testtree testtree;
private String name;
private String path;
private Set testtrees = new HashSet(0);

// Constructors

/** default constructor */
public Testtree()
{
}

/** minimal constructor */
public Testtree(String name)
{
    this.name = name;
}

/** full constructor */
public Testtree(Testtree testtree,String name,String path,Set testtrees)
{
    this.testtree = testtree;
    this.name = name;
    this.path = path;
    this.testtrees = testtrees;
}

// Property accessors

public Long getId()
{
    return this.id;
}

public void setId(Long id)
{
    this.id = id;
}

public Testtree getTesttree()
{
    return this.testtree;
}

public void setTesttree(Testtree testtree)
{
    this.testtree = testtree;
}

public String getName()
{
    return this.name;
}

public void setName(String name)
{
    this.name = name;
}

public String getPath()
{
    return this.path;
}

public void setPath(String path)
{
    this.path = path;
}

public Set getTesttrees()
{
    return this.testtrees;
}

public void setTesttrees(Set testtrees)
{
    this.testtrees = testtrees;
}

}

像这样的结构会不会引起内存的无法释放

举个例子

[code="java"]
public void SomeFunction(){
...
//这里产生了循环引用的对象
Set trees = new HashSet(0);
trees.add(b);
a.setTestTrees(trees);
b.setTestTree(a);
...
}
//SomeFunction运行完毕以后,a,b,trees都是无用对象,都会被GC收集
[/code]

应该不会。

首先从Hibernate的机理来说:

Lazy的one-to-many使用动态代理,当你访问POJO对应方法时,才会访问数据库读取该值并产生对象,如果你不访问,对象的testtrees就是个空值。

而两次从数据库读出ID相同的对象,在虚拟机中是不同的实例,但是它们的equals()方法被改写,所以看起来像是同一个东西。

因此,给定一个结点对象A,设它的子结点的父结点是B,B和A不是一个实例!所以就不会有循环引用的事情发生。
但B.equals(A),我们在使用时可以认为它们是同一个东西。

其次,从VM的GC机理来说:

Java比较先进,使用有向图(单向关联)的方式进行内存管理,有用对象指向的对象不会被收集,不被有用对象指向的值都会被GC清扫。

无用对象之间的循环引用是不会引起内存泄漏的(基于引用计数的内存管理,如C++ shared_ptr,就会引起泄漏)。