EntityManager内存消耗

时间:2012-12-06 07:48:49

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

在我们的一个项目中,用户可以将文件附加到他的帐户。我们将这些文件存储在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之前,一切都很美好,这是由java.lang.OutOfMemoryError: Java heap space方法中的uploadFile()引起的。

我做了一个堆转储并在VisualVM中查看它 Heap Dump

400多MB char[]和100 + MB byte[]。在开始时,我们的应用程序(包括JBoss)正在使用大约60-65 MB的堆。所以,问题是,为什么EntityManager像疯了一样消耗堆内存?

1 个答案:

答案 0 :(得分: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();
    }
    
  • 您可以在最终内部嵌套用于关闭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();
           }       
        }
    

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