1

我正在研究從文件讀取大量數據的應用程序。基本上,我有一個巨大的文件(大約1.5 - 2演出)包含不同的對象(約5至10百萬它們每個文件)。我需要閱讀所有這些文件,並將它們放到應用程序中的不同地圖上。問題是應用程序在某些時候讀取對象時內存不足。只有當我將它設置爲使用-Xmx4096m時,它才能處理文件。但是,如果文件會更大,它將無法再做到這一點。如何在讀取Java中的大文件時避免OutOfMemory異常

下面的代碼片段:

所有的
String sampleFileName = "sample.file"; 
FileInputStream fileInputStream = null; 
ObjectInputStream objectInputStream = null; 
try{ 
    fileInputStream = new FileInputStream(new File(sampleFileName)); 
    int bufferSize = 16 * 1024; 
    objectInputStream = new ObjectInputStream(new BufferedInputStream(fileInputStream, bufferSize)); 
     while (true){ 
      try{ 
       Object objectToRead = objectInputStream.readUnshared(); 
       if (objectToRead == null){ 
        break; 
       } 
       // doing something with the object 
      }catch (EOFException eofe){ 
       eofe.printStackTrace(); 
       break; 
      } catch (Exception e) { 
       e.printStackTrace(); 
       continue; 
      } 
     } 
} catch (Exception e){ 
     e.printStackTrace(); 
}finally{ 
    if (objectInputStream != null){ 
     try{ 
      objectInputStream.close(); 
     }catch (Exception e2){ 
      e2.printStackTrace(); 
     } 
    } 
    if (fileInputStream != null){ 
     try{ 
      fileInputStream.close(); 
     }catch (Exception e2){ 
      e2.printStackTrace(); 
     } 
    } 
} 

首先,我用的是objectInputStream.readObject()的代替objectInputStream.readUnshared(),所以它解決了部分問題。當我將內存從2048增加到4096時,它開始解析文件。 BufferedInputStream已被使用。從網上我發現只有例子如何讀取行或字節,但沒有關於對象,性能明智。

如何在不增加JVM內存的情況下讀取文件並避免出現OutOfMemory異常?有沒有辦法從文件中讀取對象,而不是在內存中保留其他任何東西?

+3

這是簡單的物理:更大的文件將需要更多的內存。那裏沒有魔法。您的文件不包含對象 - 它們包含映射到映射到對象的字符串的字節。 – duffymo

+0

如果您可以在讀取主文件時對數據進行排序,則可以使用BufferReader按行讀取文件,然後使用PrintWriter將數據追加到已存在的文件或創建新文件。 – Jure

+0

如果文件太大,別無選擇,只能將它們存儲在F.S.中。閱讀:https://commons.apache.org/proper/commons-jcs/ –

回答

1

當讀取大文件,分析對象,並讓他們在內存中有幾種解決方案與多家權衡:

  1. 可以適合所有的分析對象到內存中以便該應用程序部署在一臺服務器上。它要求以非常壓縮的方式存儲所有對象,例如使用字節或整數來存儲2個數字或在其他數據結構中進行某種移位。換句話說,將所有對象都放在可能的最小空間中。或者增加該服務器的內存(垂直縮放)

    a)然而,讀取文件可能會佔用太多內存,因此您必須以塊讀取它們。例如,這就是我正在使用JSON文件做:

    JsonReader reader = new JsonReader(new InputStreamReader(in, "UTF-8")); 
        if (reader.hasNext()) { 
         reader.beginObject(); 
         String name = reader.nextName(); 
    
         if ("content".equals(name)) { 
          reader.beginArray(); 
    
          parseContentJsonArray(reader, name2ContentMap); 
    
          reader.endArray(); 
         } 
         name = reader.nextName(); 
         if ("ad".equals(name)) { 
          reader.beginArray(); 
    
          parsePrerollJsonArray(reader, prerollMap); 
    
          reader.endArray(); 
         } 
        } 
    

    的想法是有辦法找出當某些對象的開始和結束,只讀部分。 b)如果可以的話,你也可以將文件拆分成更小的文件,那麼讀取它們會更容易。

  2. 您無法在一臺服務器上安裝該應用的所有解析對象。在這種情況下,您必須基於某些對象屬性進行分片。例如,將基於US狀態的數據拆分爲多個服務器。

希望它有助於您的解決方案。

+0

將源文件拆分成更小的文件對我來說是最有幫助的。謝謝! – Kakofonn

相關問題