【问题标题】:EntityManager memory consumptionEntityManager 内存消耗
【发布时间】:2012-11-24 05:12:00
【问题描述】:

在我们的一个项目中,用户可以将文件附加到他的帐户。我们将这些文件存储在 MS-SQL 数据库中。所以,我们有以下代码:

@Entity
public class File extends AbstractEntity {

    @Lob
    @Basic
    private byte[] data;

    @Nullable
    public byte[] getData() {
        return data;
    }

    public void setData(byte[] data) {
        this.data = data;
    }

    public File() {
    }

    public File(byte[] data) {
        this.data = data;
    }
}

public class SomeBean {

    @PersistenceContext
    protected EntityManager em;

    public Long uploadFile(@NotNull byte[] data) {
        final PhysicalFile physicalFile = new PhysicalFile();
        physicalFile.setData(data);
        em.persist(physicalFile);
        return physicalFile.getId();
    }
}

一切都很好,在我们尝试上传 40 MB 文件之前,得到了java.lang.RuntimeException: javax.transaction.RollbackException: [com.arjuna.ats.internal.jta.transaction.arjunacore.commitwhenaborted] [com.arjuna.ats.internal.jta.transaction.arjunacore.commitwhenaborted] Can't commit because the transaction is in aborted state,这是由 uploadFile() 方法中的 java.lang.OutOfMemoryError: Java heap space 引起的。

我做了一个堆转储并在 VisualVM 中查看。

char[] 的 400+ MB 和 byte[] 的 100+ MB。在开始时,我们的应用程序(包括JBoss)使用了大约 60-65 MB 的堆空间。那么问题来了,为什么EntityManager 会疯狂的消耗堆内存呢?

【问题讨论】:

    标签: java sql-server-2005 jpa out-of-memory entitymanager


    【解决方案1】:

    我对您的问题的理解如下。

    • 通过 EntityManager 加载/持久化的所有实体都保留在内存中,直到您显式地从其中分离实体(通过 EntityManager.detach() 或 EntityManager.clear() 或 EntityManager.close())。所以最好有短暂的 EntityManagers。

    • 只要在业务逻辑中发生 RuntimeException,em EntityManager 保持打开状态!你总是想避免这种 代码。您可以将创建和关闭 EntityManager 视为 如下:

      public Customer getBestCustomerOfMonth() {
      EntityManagerFactory emf = ... ;
      EntityManager em = emf.createEntityManager();
      // business logic
      em.close();
      }
      
    • 您可以在 finally 中嵌套用于关闭 EntityManager em.close(); 的行 阻止

    • 在企业应用服务器之外使用事务时 因为您必须关闭(提交或回滚)事务 与您对 EntityMangers 执行的方式相同。为了这些资源 (EntityManager 和基础交易)要关闭,你会 需要进行额外的嵌套并编写代码 类似于这个:

           public Customer updateCustomer(Customer cust) {
      
             EntityManagerFactory emf = ... ;   EntityManager em =
           emf.createEntityManager();   try {
           EntityTransaction t = em.getTransaction();
           try {
             t.begin();  
             // business logic to update the customer
             em.merge(cust);
             t.commit();
           } finally {
             if (t.isActive()) t.rollback();
           }   } finally {
           em.close();
             }       
          }
      

    您可能认为这种嵌套结构看起来有点乱,但它确实需要在事务的前面。

    【讨论】:

      猜你喜欢
      • 2010-10-12
      • 1970-01-01
      • 2011-10-03
      • 2013-10-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多