2011-04-14 71 views
1

我有一個MySQL表1M行,我是Java持久性API當我執行下面的代碼,然後我得到Java堆錯誤:的Java持久性內存泄漏

int counter = 0; 
while (counter < 1000000) { 
    java.util.Collection<MyEntityClass> data = myQuery.setFirstResult(counter) 
     .setMaxResults(1000).getResultList(); 
    for(MyEntityClass obj : data){ 
     System.out.println(obj); 
    } 
    counter += 1000; 
} 
+8

你有人點擊「下一步」2500次? – 2011-04-14 14:38:02

回答

7

我不知道的JTable真的掛到當你點擊「下一步」時,所有這些舊的參考文獻。我不相信這是一個持久性問題。無論支持JTable的數據結構如何,我都要確保在添加下一批記錄之前將其清除。這樣,舊值可以被GC'd。

您的JTable不應該有ResultSet。最好有一個持久層來隱藏客戶的這些細節。查詢一批值(而不是整個數據集的),將其從ResultSet加載到數據結構中,然後在finally塊中關閉ResultSet和Statement。您需要在創建它們的方法範圍內關閉這些資源,或者您要求麻煩。

+1

我不建議一次檢索1M行,出於內存和性能原因。請參閱我的回答,以獲得有關您在用戶下次點擊時檢索網頁的建議。 – AndyT 2011-04-14 15:28:03

+0

我不建議檢索1M行,每次都對子集進行查詢,將其加載到數據結構中,然後關閉,我將編輯我的問題以進行說明 – duffymo 2011-04-14 17:23:30

0

看起來你的結果集在他的特殊情況下不適用於GC。檢查你的代碼,看看這個結果集的鏈接真的在哪裏發生,從而發生內存泄漏。

1
  • 這是一個Java EE或Java SE應用程序?
  • 你是如何處理你的實體經理 ?

實體管理器典型地與上下文相關聯。在事務處理期間,您恢復的每個實體都將放入其中,並且它將成爲所有實體的緩存,當事務提交時,JPA將在上下文中搜索修改並將更改提交到數據庫。

這意味着,如果恢復一個百萬行,你會在你的背景百萬的實體,直到您關閉實體管理器,他們不會被垃圾收集的。

由於您指的是JTable,我只能假設這是一個JSE應用程序。在這種類型的應用程序中,您完全控制了上下文。在這種類型的應用程序中,上下文和實體管理器之間存在一對一的關係(在Java EE環境中並非總是如此)。

這意味着您可以創建每個請求的實體管理器(即交易或交談)或實體管理器應用程序的整個生命週期。

如果您使用的是第二種方法,你情境永遠不會被垃圾收集,並從更大變得讀取數據庫中的多個對象,直到你最終可能會達到內存的問題像你描述的那個。

我不是說這是你的問題的原因,但它肯定會是在尋找根本原因帶了好頭,你不覺得嗎?

+0

沒有提及我可以看到的JPA。如果他/她使用直接JDBC,因爲我懷疑它們是,那麼這些都不適用。 – duffymo 2011-04-14 14:54:46

+0

@duffymo它在問題的標記上 – 2011-04-14 14:58:29

+0

nope,我沒有直接使用jdbc我有一個實體類,它對應於我的表 – user704006 2011-04-14 15:04:52

2

問題幾乎可以肯定的是你的resultSet對象正在緩存整個結果集,這會爲這麼大的查詢消耗大量的內存。

不像現在那樣重置結果集上的索引 - 它不清除緩存的結果,我建議你編寫一個查詢來檢索給定頁面的相應行,並且每次執行頁面更改。每次丟棄舊的結果集,以確保您不會緩存任何內容。

根據您使用的數據庫,您可以使用rownum僞列(Oracle),row_number()(DB2,MSSQL)函數或limit x offset y語法(MySql)。

+0

+1巨大的結果集不好。 – 2011-04-14 15:30:34