在 Hibernate 实体持久化期间发生巨大的内存泄漏,为什么?

Huge memory leak during Hibernate entity persisting, why?

我将 Hibernate 与 JPA EntityManager 一起使用,而不是 Hibernate 会话。大多数人似乎都建议为每个事务使用一个新的 EntityManager,所以这就是我正在做的。

因此,我连续创建了 10000 个新实体。第一次迭代的堆使用量约为 90 MB,最后一次迭代为 5 GB。

这是我的迭代代码:

    Session session = Core.getDatabase().createEntityManager().unwrap(Session.class);
    Query query = session.getNamedQuery("Account.getAllIds");
    query.setReadOnly(true);
    query.setFetchSize(100);
    ScrollableResults accounts = query.scroll(ScrollMode.FORWARD_ONLY);

    EntityManager entityManager = Core.getDatabase().createEntityManager();
    entityManager.getTransaction().begin();

    while (accounts.next()) {

        int id = (int) accounts.get(0);
        Account account = entityManager.getReference(Account.class, id);

        Core.getDatabase().persist(new AccountTest(account));
        changes++;

    }

    entityManager.close();
    accounts.close();
    session.close();

还有我的持久化函数:

public class Database
{
    private final EntityManagerFactory entityManagerFactory;

    public Database(String host, String database, String user, String password)
    {
        Map<String, Object> properties = new HashMap<String, Object>();
        properties.put("javax.persistence.jdbc.url", "jdbc:mysql://" + host + ":3306/" + database);
        properties.put("javax.persistence.jdbc.user", user);
        properties.put("javax.persistence.jdbc.password", password);

        entityManagerFactory = Persistence.createEntityManagerFactory("default", properties);
    }

    public EntityManager createEntityManager()
    {
        return entityManagerFactory.createEntityManager();
    }

    public void persist(Object... objects)
    {
        EntityManager entityManager = createEntityManager();
        entityManager.getTransaction().begin();

        for (Object object : objects) {
            entityManager.persist(object);
        }

        entityManager.getTransaction().commit();
        entityManager.clear();
        entityManager.close();
    }
}

所以我遍历所有帐户实体(10k,但由于滚动功能而使用 Hibernate Session)并想为每个帐户创建一个新的 AccountTest。

问题是您一直保持第一个 EntityManager 打开,而只清除并关闭另一个 EntityManager,它仅用于保留一个项目。

最后,您在第一个 EntityManager 中加载了所有帐户实体。