在我们的一个项目中,用户可以将文件附加到他的帐户。我们将这些文件存储在 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 中查看了它。
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/