0

ファイルを読み取って、同じ最初のトークン (readId) を共有する行をセット (文字列) に保存しようとしています。各セットは私のハッシュマップの一部です >.

すでにヒープを 32 ギガに増やし、string.split から StringTokenizer に移動しましたが、まだこのエラーが発生しています:

Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
    at java.util.Arrays.copyOfRange(Arrays.java:2694)
    at java.lang.String.<init>(String.java:203)
    at java.lang.String.substring(String.java:1913)
    at java.util.StringTokenizer.nextToken(StringTokenizer.java:352)
    at java.util.StringTokenizer.nextElement(StringTokenizer.java:407)
    at Simple1_BootStrap.createMapSet(Simple1_BootStrap.java:68)
    at Simple1_BootStrap.main(Simple1_BootStrap.java:206)

以前は、次の行によって「メモリ不足エラー」が生成されていました。

Set<String> s =new TreeSet<String>();

エラーを生成するコードの一部は次のとおりです。

Map<String,Set<String>> map2 = new HashMap<String,Set<String>>();

    try{          
          BufferedReader br = new BufferedReader(new FileReader(filename)); 

          String strLine;
          String readId; 
          while ((strLine = br.readLine()) != null)   {
              alignment ++;
              StringTokenizer stringTokenizer = new StringTokenizer(strLine);

              readId = stringTokenizer.nextElement().toString();  

              if(map2.containsKey(readId)) {
                    Set<String> s = map2.get(readId);
                    s.add(strLine);
                    map2.put(readId, s);
                  }
                  else {
                      Set<String> s =new TreeSet<String>();
                      s.add(strLine);
                      map2.put(readId, s);
                  }
          }

          br.close();         
                      }catch (Exception e){//Catch exception if any
              System.err.println("Error: " + e.getMessage());
          }

ハッシュマップ内のエントリをランダムに選択し、関連するセットを読み取って、入力ファイルと同様のファイルを作成する必要があるため、これらの行をセット内に配置しました。

「メモリ不足エラー」を回避するための別のアプローチを誰かが提案できますか?

ありがとうございました。

4

2 に答える 2

2

文字列を読み取るときは、ファイルの場合の 2 ~ 4 倍のメモリを使用することを期待する必要があります。これは、各文字が 2 バイトを使用するのに対し、各 String オブジェクト +char[]は約 80 バイトのメモリを使用するためです。たとえば、4 文字の String は約 88 バイトを使用します。

これを HashMap に追加すると、レコードごとに約 100 バイトが必要になります。

要するに、これよりもはるかに多くのメインメモリがあると仮定して、少なくとも 100 GB のヒープを試してみます。


解決策:

これだけの記憶がない場合は、アプローチを再考することをお勧めします。たとえば、ファイルをメモリ マップして、ヒープ上にまったく置かないようにし、Trove コレクションを使用して、インデックスにオブジェクトを使用せずにインデックスでデータを参照することができます。

于 2013-11-14T16:16:11.263 に答える
2

すべてをメモリにロードするという知恵に関係なく、 Java 7 の最近のビルドString.substring()より前のバージョンの Java の元の (より大きな) 文字列への参照を保持します。詳細については、この質問/回答を参照してください。

コンストラクターを使用しString(String)て結果から新しい文字列を作成するStringTokenizerと、最近の Java 7 ランタイムにアップグレードする場合と同様に、これが軽減されます。

于 2013-11-14T16:13:09.930 に答える