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. あなたが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. そのアプリケーションのすべての解析済みオブジェクトを1つのサーバーに収めることはできません。この場合、オブジェクトのプロパティに基づいて分割する必要があります。例えば、米国の州に基づくデータを複数のサーバーに分割する。

うまくいけば、あなたのソリューションに役立ちます。

+0

私の場合、ソースでファイルを小さなものに分割することが最も効果的でした。ありがとうございました! – Kakofonn

関連する問題