在我们的一个项目中,用户可以将文件附加到他的帐户。我们将这些文件存储在 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 中查看它。
400+ MBchar[]
和 100+ MB 的byte[]
. 在开始时,我们的应用程序,包括JBoss
,正在使用大约 60-65 MB 的堆。那么问题来了,为什么要EntityManager
疯狂地消耗堆内存呢?