【问题标题】:Out of Memory When Loading Java Entities加载 Java 实体时内存不足
【发布时间】:2011-02-27 01:23:37
【问题描述】:

我有一个可怕的问题,希望有一个非常简单的答案。执行基本操作时内存不足

如果我有这样的代码:

MyEntity myEntity;
for (Object id: someIdList) {
   myEntity = find(id); 
   // do something basic with myEntity
}

而find()方法是标准的EntityManager相关方法:

public MyEntity find(Object id) {
    return em.find(mycorp.ejb.entity.MyEntity.class, id);
}

这段代码在几周前工作过,如果数据库中的项目较少,它也能正常工作。我面临的结果错误是:

java.lang.OutOfMemoryError: 超出 GC 开销限制

异常来自 oracle toplink 调用一些 oracle jdbc 方法。

之所以存在循环,是因为当有大量记录时,诸如“从 MyEntity 中选择 object(o) as o”之类的 EJBQL 会使应用程序服务器过载。

【问题讨论】:

  • 执行 em.clear() 不是我正在寻找的答案......但我会记住它。这个问题的问题在于它曾经可以工作......使用相同级别的数据库条目!这引发了另一个问题——如果我有一个循环,我可以定期刷新/清除..但是当应用程序只是长时间运行时呢? EntityManager 应该管理它管理的数量!
  • EntityManager 大部分时间的生命周期都很短(常见的模式是 entitymanager-per-request)。我建议阅读5.1. Entity manager and transaction scopes。如果您不遵循这种模式,那么您将不得不处理“内存处理”。 EntityManager 将实体保存在内存中以跟踪更改,这就是 JPA 的工作方式,您不能合理地期望 EntityManager 能够为您加载整个数据库或刷新更改并分离实体。

标签: java jpa jakarta-ee ejb-3.0


【解决方案1】:

这段代码在几周前工作过,如果数据库中的项目较少,它也能正常工作。我面临的结果错误是:java.lang.OutOfMemoryError: GC overhead limit exceeded

这里没有什么令人惊讶的。 em.find() 加载的实体被放置并保存在持久性上下文(内存中)中以跟踪更改,因此如果您在没有预防措施的情况下批量加载太多实体,您只会爆炸您的内存并获得 OOME。

如果您确实需要对所有实体进行操作,您需要先调用 flush() 将所有更改推送到数据库,然后然后再调用 clear() 定期清除持久化上下文并释放内存:

int i = 0;
for (Object id: someReallyBigIdList) {
    myEntity = find(id); 
    // do something basic with myEntity
    if ( i % 20 == 0 ) { //20, same as the JDBC batch size
        //flush a batch of DML operations and release memory:
        em.flush();
        em.clear();
    }
    i++;
}

调用clear() 会导致所有托管实体分离。对尚未刷新到数据库的实体所做的更改将不会被持久化因此需要先flush() 进行更改

【讨论】:

    【解决方案2】:

    问题是,如果您执行循环,您只是查询一个又一个实体,但它仍然在您的 EntityManager 中被引用。你必须要么

    • clear() entityManager,或
    • 从中删除实体(忘记了如何调用它的函数)。

    如果可能,将实体管理器设置为只读也是一个好主意,因为这会阻止 JPA 将每个对象的副本保存在内存中,只是为了检测在 flush() 到数据库。

    【讨论】:

    • 我刚刚在 Hibernate 中遇到了一个问题,将实体设置为只读并不意味着它会停止持久上下文以在持久上下文中保存副本,它仍然会保留,因为后续加载/查找将从持久上下文而不是数据库中获取副本。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-09-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多