如我有一颗自引用的树,简单的结构如: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,就会引起泄漏)。