2015-05-07 81 views
2

我使用Hibernate和JPA EntityManager,而不是Hibernate會話。大多數人似乎都建議爲每個事務使用一個新的EntityManager,所以這就是我正在做的事情。在Hibernate實體持久化過程中內存泄露很大,爲什麼?

因此,我創建了10000個新的實體連續。第一次迭代時堆的使用量約爲90 MB,最後一次約爲5 GB。

java memory leak

這是我的迭代代碼:

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(); 

而且我的堅持功能:

所以我遍歷所有帳戶實體(10K,但使用Hibernate的Session由於滾動功能)並且想爲每個帳戶創建一個新的AccountTest。

+3

這不是內存泄漏,這就是所謂的會話緩存。您需要了解JPA如何工作。 –

+0

是em.clear(); em.close(); em.finalize();尚未清除緩存?我需要撥打什麼? – Aich

回答

3

問題是你持有第一個EntityManager開放的整個時間,而只清除和關閉另一個EntityManager這只是用於堅持一個項目。

最後,您已將所有帳戶實體加載到第一個EntityManager中。

+0

感謝您的回答。我使用第一個EM爲每個帳戶ID調用getReference。我應該爲每個getReference調用創建一個新的EM,還是我可以用「a = new Account(); a.setId(id)」替換getReference調用,因爲我可以完全確定數據庫中存在ID? – Aich

+0

如果您確定數據庫中存在'Account',那麼Hibernate允許您使用具有其id設置的瞬態實體來引用實體。這個特性是Hibernate特有的,它不是JPA標準。 –