2012-04-22 115 views
0

我有一個應用程序遍歷一定數量的resultSets並查詢來自其他表的每一行的附加信息。Java SQL查詢內存泄漏

粗糙的結構是這樣的:

public void main(String[] args) { 
    ResultSet result = database.connection.createStatement() 
          .executeQuery("SELECT * FROM entities"); 
    ArrayList<Entity> entities = new ArrayList<Entity>(); 
    while (result.next() { 
     Entity entity = EntityFactory.createById(result.getInt("id")); 
     entities.add(entity); 
    } 
} 

// EntityFactory 
public static Entity createById(int id) { 
    StringBuilder sql = new StringBuilder("SELECT * FROM sampling_data WHERE id = ") 
          .append(id); 
    ResultSet result = database.connection.createStatement() 
          .executeQuery(sql.toString()); 
    result.first(); 
    EntityData data = new EntityData(25); 

    for (int sample = 1; sample <= 25; sample++) { 
     String sample_R = new StringBuilder("sample_") 
           .append(sample).append("_R").toString(); 
     String sample_G = new StringBuilder("sample_") 
           .append(sample).append("_G").toString(); 
     String sample_B = new StringBuilder("sample_") 
           .append(sample).append("_B").toString(); 

     int r = resultSet.getInt(sample_R); 
     int g = resultSet.getInt(sample_G); 
     int b = resultSet.getInt(sample_B); 

     data.add(r, g, b); 
    } 

    return new Entity(data); 
} 

這會導致OutOfMemoryException異常。

我該如何讓循環(或整個方法)更高效地存儲內存?

+0

哦,你需要[VisualVM的(http://visualvm.java.net/)或這樣......多少結果你在'ResultSet中有有'? – yair 2012-04-22 11:48:02

+0

我有VisualVM,它的HeapDump顯示'String'和'char []'用完了大約95%的堆。結果集大約2500行,但將來會變得更大。 – 2012-04-22 11:51:27

+1

在你的主要方法中,你是在查詢這75個'sample_ *'列還是其他列?在數據庫中存儲類似RBG樣本並將每個樣本映射到其自己的對象可能不是最好的方法。你想在這裏實現的總體目標是什麼? – 2012-04-22 11:59:20

回答

0

最大的問題是(我認爲)createById沒有關閉結果集和語句。 此外,沒有nx1查詢是有意義的。

try { 
     Statement stmt = database.connection.createStatement(); 
     ResultSet result = stmt.executeQuery("SELECT * FROM sampling_data d" 
      + " WHERE EXISTS(SELECT * FROM entities e WHERE e.id = d.id)"); 
     List<Entity> entities = new ArrayList<Entity>(); 
     while (result.next()) { 
      Entity entity = EntityFactory.createById(result); 
      entities.add(entity); 
     } 
     result.close(); 
     stmt.close(); 
    } catch (SQLException ex) { 
     Logger.getLogger(Test1.class.getName()).log(Level.SEVERE, null, ex); 
    } 

而且

// EntityFactory 
public static Entity createById(ResultSet resultSet) { 
    EntityData data = new EntityData(25); 
    for (int sample = 1; sample <= 25; sample++) { 
     String sample_R = new StringBuilder("sample_").append(sample).append("_R").toString(); 
     String sample_G = new StringBuilder("sample_").append(sample).append("_G").toString(); 
     String sample_B = new StringBuilder("sample_").append(sample).append("_B").toString(); 
     int r = resultSet.getInt(sample_R); 
     int g = resultSet.getInt(sample_G); 
     int b = resultSet.getInt(sample_B); 

     data.add(r, g, b); 
    } 

    return new Entity(data); 
} 
0

從代碼的瞥見中有點難以分辨,但我認爲它與完全獲取的行數過多有關。

您應該在Statement上使用setFetchSize(int rows),其行數合理(可能爲100)。

private static int FETCH_SIZE = 100; 
    ... 
    Statement stmt = databaseConnection.createStatement() 
    stmt.setFetchSize(); 
    ResultSet result = stmt.executeQuery("SELECT * FROM sampling_data"); 
0

似乎調用getInt()方法在循環中執行 時使用了大量的存儲器。

這是不正確的。 getInt()沒有什麼特別的,會導致你的問題。

您的模式破壞了關係數據庫的第一範式。看到sample_1_R, sample_1_G, sample_1_B也讓我質疑你的其他決定。這顯然是1:m的關係。像數字25一樣的幻數。

我想知道爲什麼你要用String builder和int來做所有這些事情。我將這些RGB值封裝到一個有意義的對象中,如java.awt.Color

我們在這裏談論的數據量是多少?

25*3*32*2500 ~ 5.7 MB 

這對於您的2500行並不多,每行有75個整數值。還有其他一些事情正在發生,從您的代碼中看不清楚。

更新:

你讓這段代碼的經典(n+1)查詢錯誤。你得到所有的實體,然後遍歷它們以獲得RGB值。我建議做一個JOIN並將它們一次全部帶回。這可能無法解釋你的記憶問題,但這是一個問題。

當您查詢RGB值時,您重複建立列名稱。這完全是浪費。將它們作爲數組中的static final String實例。

+0

我編輯了我的代碼並添加了以前在評論中跳過的所有內容。也許現在更容易找到錯誤? – 2012-04-22 12:38:54