2011-09-15 60 views
-1

我目前正在編寫一個Java應用程序來從數據庫中檢索BLOB類型的數據,我使用查詢來獲取所有數據並將它們存儲在Map<String, Object>的列中。當我需要使用數據時,我重複列表以獲取信息。Java OutOfMemoryError

但是,當我試圖獲取行列表超過幾次時,我得到了一個OutOfMemoryError。我是否需要在代碼中釋放內存?我的代碼如下:

ByteArrayInputStream binaryStream = null; 
OutputStream out = null; 
try { 
    List<Map<String, Object>> result = 
    jdbcOperations.query(
     sql, 
     new Object[] {id}, 
     new RowMapper(){ 
      public Object mapRow(ResultSet rs, int i) throws SQLException { 
      DefaultLobHandler lobHandler = new DefaultLobHandler(); 
      Map<String, Object> results = new HashMap<String, Object>(); 
      String fileName = rs.getString(ORIGINAL_FILE_NAME); 
      if (!StringUtils.isBlank(fileName)) { 
       results.put(ORIGINAL_FILE_NAME, fileName); 
      } 
      byte[] blobBytes = lobHandler.getBlobAsBytes(rs, "AttachedFile"); 
      results.put(BLOB, blobBytes); 

      int entityID = rs.getInt(ENTITY_ID); 
      results.put(ENTITY_ID, entityID); 
      return results; 
      } 
     } 
    ); 

    int count = 0; 
    for (Iterator<Map<String, Object>> iterator = result.iterator(); 
     iterator.hasNext();) 
    { 
    count++; 
    Map<String, Object> row = iterator.next(); 
    byte[] attachment = (byte[])row.get(BLOB); 
    final int entityID = (Integer)row.get(ENTITY_ID); 
    if(attachment != null) { 
     final String originalFilename = (String)row.get(ORIGINAL_FILE_NAME); 
     String stripFilename; 
     if (originalFilename.contains(":\\")) { 
     stripFilename = StringUtils.substringAfter(originalFilename, ":\\"); 
     } 
     else { 
     stripFilename = originalFilename; 
     } 
     String filename = pathName + entityID + "\\"+ stripFilename; 

     boolean exist = (new File(filename)).exists(); 

     iterator.remove(); // release the resource 

     if (!exist) { 
     binaryStream = new ByteArrayInputStream(attachment); 
     InputStream extractedStream = null; 
     try { 
      extractedStream = decompress(binaryStream); 
      final byte[] buf = IOUtils.toByteArray(extractedStream); 
      out = FileUtils.openOutputStream(new File(filename)); 
      IOUtils.write(buf, out); 
     } 
     finally { 
      IOUtils.closeQuietly(extractedStream); 
     } 
     } 
     else { 
     continue; 
     } 
    } 
    } 
} 
catch (FileNotFoundException e) { 
    e.printStackTrace(); 
} 
catch (IOException e) { 
    e.printStackTrace(); 
} 
finally { 
    IOUtils.closeQuietly(out); 
    IOUtils.closeQuietly(binaryStream); 
} 

回答

1

考慮重新組織代碼,以免一次將所有斑點保留在內存中。不要將它們全部放入結果地圖中,而是在檢索它時輸出每一個地圖。

有關擴大內存設置的建議也很好。

+0

這也是我的想法,因爲我不希望我的應用程序在另一臺計算機上運行時需要更改JVM設置。但是這樣我可能需要多次查詢數據庫,並且非常仔細地將結果分組以便不會錯過任何行。 – newguy

+0

我修改了我的代碼和查詢,以便它基於一系列ID執行查詢,並且OutOfMemory再也不會發生。 – newguy

+0

也許我錯過了一些東西,但是......我想你「只是」需要用一個將blob保存到磁盤的方法來調用「put()」代碼 - 寫入方法的第二部分。將其拆分成單獨的方法將使代碼更易於理解。然後你的mapRow()函數不必返回任何重要的東西 - 你不會使用返回值。 –

1

你的Java虛擬機可能不使用所有的內存它可以。您可以對其進行配置以從操作系統獲得更多信息(請參見How can I increase the JVM memory?)。這將是一個快速而簡單的解決方案。如果你仍然內存不足,看看你的算法 - 你是否真的需要一次在內存中的所有這些BLOB?