0

我正在尝试读取文件并将共享相同第一个令牌(readId)的行保存在一组(字符串)中。每个集合都是我的哈希图的一部分 >。

我已经将堆增加到 32 giga,也从 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

无论将所有内容加载到内存中是否明智,都String.substring()保留对 Java 7 最近构建之前的 Java 版本的原始(更大)字符串的引用。因此,您可能持有比您想象的更多的内存。有关更多详细信息,请参阅此问题/答案

使用String(String)构造函数从结果中构建一个新的字符串StringTokenizer可以缓解这种情况,升级到最近的 Java 7 运行时也可以。

于 2013-11-14T16:13:09.930 回答
2

当您读取字符串时,您应该期望它使用的内存是文件中的 2-4 倍。这是因为每个字符使用两个字节,但每个 String 对象 +char[]使用大约 80 个字节的内存,例如 4 个字符的字符串使用大约 88 个字节。

当您将它添加到 HashMap 时,每条记录需要大约 100 个字节。

简而言之,假设您的主内存比这多得多,我会尝试至少 100 GB 的堆。


一个解法:

如果你没有这么多的记忆,我建议你重新考虑你的方法。例如,您可以对文件进行内存映射,使其根本不在堆上,并使用 Trove 集合按索引引用您的数据,而不使用索引对象。

于 2013-11-14T16:16:11.263 回答