JPA / Hibernate 内存不足异常
JPA / Hibernate Out of Memory Exception
我最近将一个使用本机 Hibernate 实体和会话管理的项目移到了 Spring,带有注解驱动的依赖注入和事务管理。
我有一个像这样的实体结构:
@Entity
@Table(name = "PARENT",uniqueConstraints=@UniqueConstraint(columnNames={"parentName"}))
public class Parent implements Serializable, {
static final long serialVersionUID = 1L;
@Id
private int id;
@OneToMany(mappedBy = "parent", fetch = FetchType.EAGER, cascade = CascadeType.ALL)
private Set<Child> child = new HashSet<Child>();
}
@Entity
@Table(name = "CHILD", uniqueConstraints = @UniqueConstraint(columnNames = {
"childName", "parent_id" }))
@SequenceGenerator(name = "CHILD_SEQ", allocationSize = 1, sequenceName = "CHILD_SEQ")
public class Child implements Serializable {
static final long serialVersionUID = 1L;
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "CHILD_SEQ")
private int id;
private String childName = ""; //$NON-NLS-1$
@ManyToOne
@JoinColumn(name = "parent_id")
private Parent parent;
}
事情是这样的。
我得到了所有包含单独的子对象列表的父对象。这工作很快,我的调试器内存中有完整的对象树,我可以看到每个子对象都已正确加载。
public List<Parent> getParents() {
return em.createQuery("from Parent",Parent.class).getResultList();
}
然后我尝试获取每个 Child 对象,应用程序冻结我的 PC 速度变慢,几个小时后我得到了内存不足异常。
public List<Child> getChildren() {
return em.createQuery("from Child",Child.class).getResultList();
}
我查看了生成的 SQL,对于第一种方法,它似乎在逻辑上将调用分解为各个对象集,并且在几秒钟内它似乎构建了一个我可以构建的巨型查询没有真正关注并且该查询似乎没有返回,虽然我真的不能告诉。
我无法理解的是,为什么对父级的查询工作得如此之快,并为我提供了每一个对象,但子级查询却中断了。
这可能是内存泄漏导致的。
您可以使用 space 增加堆。
-Xms<size> set initial Java heap size
-Xmx<size> set maximum Java heap size
http://javarevisited.blogspot.com.ng/2011/09/javalangoutofmemoryerror-permgen-space.html
但是,很高兴知道 java.lang.OutOfMemoryError 的原因:Java 堆 space。使用探查器可以帮助您找出是什么占用了堆大小。
如果您使用的是 Netbeans,则可以使用 https://profiler.netbeans.org/
或找到与您的 IDE.
兼容的探查器
当您从 parents 开始时,Hibernate 可以读取所有 parents(简单)并加入 child table(同样,简单)。每个child正好有一个parent,也就是我们加入的那个,这样就够了。虽然整个数据库都被读入内存,但没有问题,因为它很小。
另一方面,当您从 children 开始时,Hibernate 必须首先为每个 child 获取 parent。这意味着一个加入 parent table。但是,那些parent人有children,所以我们必须再次加入childtable才能找到他们。
您的 类 不完整,parent 姓名丢失,您提到了其他 collection。如果其他 collection 也很急切,则必须使用第一个 child 级别和第二个 child 级别的连接来获取它们,每个 [=22 添加两个连接=].这使得查询非常复杂!
我最近将一个使用本机 Hibernate 实体和会话管理的项目移到了 Spring,带有注解驱动的依赖注入和事务管理。
我有一个像这样的实体结构:
@Entity
@Table(name = "PARENT",uniqueConstraints=@UniqueConstraint(columnNames={"parentName"}))
public class Parent implements Serializable, {
static final long serialVersionUID = 1L;
@Id
private int id;
@OneToMany(mappedBy = "parent", fetch = FetchType.EAGER, cascade = CascadeType.ALL)
private Set<Child> child = new HashSet<Child>();
}
@Entity
@Table(name = "CHILD", uniqueConstraints = @UniqueConstraint(columnNames = {
"childName", "parent_id" }))
@SequenceGenerator(name = "CHILD_SEQ", allocationSize = 1, sequenceName = "CHILD_SEQ")
public class Child implements Serializable {
static final long serialVersionUID = 1L;
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "CHILD_SEQ")
private int id;
private String childName = ""; //$NON-NLS-1$
@ManyToOne
@JoinColumn(name = "parent_id")
private Parent parent;
}
事情是这样的。
我得到了所有包含单独的子对象列表的父对象。这工作很快,我的调试器内存中有完整的对象树,我可以看到每个子对象都已正确加载。
public List<Parent> getParents() { return em.createQuery("from Parent",Parent.class).getResultList(); }
然后我尝试获取每个 Child 对象,应用程序冻结我的 PC 速度变慢,几个小时后我得到了内存不足异常。
public List<Child> getChildren() { return em.createQuery("from Child",Child.class).getResultList(); }
我查看了生成的 SQL,对于第一种方法,它似乎在逻辑上将调用分解为各个对象集,并且在几秒钟内它似乎构建了一个我可以构建的巨型查询没有真正关注并且该查询似乎没有返回,虽然我真的不能告诉。
我无法理解的是,为什么对父级的查询工作得如此之快,并为我提供了每一个对象,但子级查询却中断了。
这可能是内存泄漏导致的。 您可以使用 space 增加堆。
-Xms<size> set initial Java heap size
-Xmx<size> set maximum Java heap size
http://javarevisited.blogspot.com.ng/2011/09/javalangoutofmemoryerror-permgen-space.html
但是,很高兴知道 java.lang.OutOfMemoryError 的原因:Java 堆 space。使用探查器可以帮助您找出是什么占用了堆大小。 如果您使用的是 Netbeans,则可以使用 https://profiler.netbeans.org/ 或找到与您的 IDE.
兼容的探查器当您从 parents 开始时,Hibernate 可以读取所有 parents(简单)并加入 child table(同样,简单)。每个child正好有一个parent,也就是我们加入的那个,这样就够了。虽然整个数据库都被读入内存,但没有问题,因为它很小。
另一方面,当您从 children 开始时,Hibernate 必须首先为每个 child 获取 parent。这意味着一个加入 parent table。但是,那些parent人有children,所以我们必须再次加入childtable才能找到他们。
您的 类 不完整,parent 姓名丢失,您提到了其他 collection。如果其他 collection 也很急切,则必须使用第一个 child 级别和第二个 child 级别的连接来获取它们,每个 [=22 添加两个连接=].这使得查询非常复杂!