java - EntityManager 内存消耗

标签 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] 无法提交,因为事务处于中止状态,这是由 java.lang.OutOfMemoryError: Java 引起的uploadFile() 方法内的堆空间

我制作了堆转储并在 VisualVM 中查看了它。
Heap Dump

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

最佳答案

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

  • 通过 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(); 的代码嵌套在 finally 中 block

  • 在企业应用程序服务器外部使用事务时 因为您必须关闭(提交或回滚)事务 与处理 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();
           }       
        }
    

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

关于java - EntityManager 内存消耗,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13739120/

相关文章:

java - 在 Java 中加载 DSA 公钥

java - Spring ConfigurationProperties 可与流畅的 setter 或自定义 setter 一起使用

sql-server - Sql Server中如何计算读写比?

sql-server-2005 - 检查表变量是否存在?

java - 为什么这会创建强制关闭

c# - 来自存储过程的模式

java - 从 JPA 中排除类中的字段

java - CriteriaBuilder 连接/子查询与结果整数

java - 具有集合的JPA实体针对分离成员上的contains方法返回false

java - Eclipse 动态 Web 应用程序将 jar 文件放入 WEB-INF/lib 和 Java 构建路径