2010-10-13 63 views
0

我有一个应用程序,它形成所有可能的配对,然后比较这些配对,但是当我运行该应用程序时,它给了我例外:OutOfMemoryError:运行时的Java堆空间码。我尝试了-Xmx1500m,但例外情况一直在持续。 用于产生对所述代码被如下异常:OutOfMemoryError:运行代码时的Java堆空间

File file = ...; 

final Map<Pair, Collection<Integer>> lineNumbersByPair = new HashMap<Pair, Collection<Integer>>(); 

/* 
* Step 1: Read in the lines, one by one. 
*/ 
Reader reader = new FileReader(file); 
try { 
    BufferedReader bufferedReader = new BufferedReader(reader); 
    try { 
     String line; 

     int lineNumber = 0; 
     while ((line = bufferedReader.readLine()) != null) { 
      lineNumber++; 

      String[] tokens = line.split("\\s+"); 
      int[] values = new int[tokens.length]; 

      for (int i = 0; i < tokens.length; i++) { 
       values[i] = Integer.parseInt(tokens[i]); 
      } 

      for (int i = 0; i < values.length; i++) { 
       for (int j = i + 1; j < values.length; j++) { 
        Pair pair = new Pair(values[i], values[j]); 

        Collection<Integer> lineNumbers; 
        if (lineNumbersByPair.containsKey(pair)) { 
         lineNumbers = lineNumbersByPair.get(pair); 
        } else { 
         lineNumbers = new HashSet<Integer>(); 
         lineNumbersByPair.put(pair, lineNumbers); 
        } 
        lineNumbers.add(lineNumber); 
       } 
      } 
     } 
    } finally { 
     bufferedReader.close(); 
    } 
} finally { 
    reader.close(); 
} 

/* 
* Step 2: Identify the unique pairs. Sort them according to how many lines they appear on (most number of lines to least number of lines). 
*/ 
List<Pair> pairs = new ArrayList<Pair>(lineNumbersByPair.keySet()); 
Collections.sort(
     pairs, 
     new Comparator<Pair>() { 
      @Override 
      public int compare(Pair pair1, Pair pair2) { 
       Integer count1 = lineNumbersByPair.get(pair1).size(); 
       Integer count2 = lineNumbersByPair.get(pair2).size(); 
       return count1.compareTo(count2); 
      } 
     } 
    ); 
Collections.reverse(pairs); 

/* 
* Step 3: Print the pairs and their line numbers. 
*/ 
for (Pair pair : pairs) { 
    Collection<Integer> lineNumbers = lineNumbersByPair.get(pair); 
    if (lineNumbers.size() > 1) { 
     System.out.println(pair + " appears on the following lines: " + lineNumbers); 
    } 
} 

我读围绕15MB一个文件,它包含如单数的20000lines,并有围绕每行40个数字,它形成的所有可能的对每条线的。 任何人有任何想法如何解决这个问题?谢谢

+1

你会得到适当的结果较小的文件?迄今为止的成功输出? – 2010-10-13 04:51:42

+0

是的,它可以在较小的文件上正常工作,并且输出结果都很好 – starcaller 2010-10-13 04:52:34

+0

starcaller,正如J-16 SDiZ所评论的,正如我发布的那样 - 这个问题将会成为内存和时间破坏者。你真正想要解决的用例或问题是什么? – birryree 2010-10-13 05:05:28

回答

1

我的数学可能会关闭,但这可能就是为什么您的空间不足。

所以每行有40个数字,20000行= 800000个数字。

800000 C 2 = 319999600000数字的组合。

在4个字节的一个intPair<int, int>,每对至少8个字节,然后您将它添加到您的数据结构。

8字节* 319999600000 = 2兆兆字节。

重新读你的问题后,每一行都与下一行分开。

每行40个数字=> 40 C 2 =每行780个组合* 20000行= 15600000可能的唯一对数*每对8个字节= 119 MB纯粹用于int最糟糕的情况。再加上引用占用的内存,因为Java不允许集合中的原始类型。

但是我们再看一下你的程序后,我有一些建议:

你为什么映射PairSet<Integer>

如果您只对每个Pair的出现次数感兴趣,则不需要跟踪对的出现的行号 - 您只需要存储它出现的次数。

因此,在这种情况下,您想将Pair映射到Integer。这可能会减少您需要的内存量。

您是否在意这一对的订购?

您的for循环似乎表明您不关心排序,即对(30,45)与对(45,30)相同。如果是这样,你应该创建你的Pair根据对中的相对顺序。也许首先根据最小值创建一个Pair,这样每次遇到两个整数m和n时,总是会创建一对为Pair(m, n)。另见下一节关于hashCode()equals()

您是否实施了Pairint hashCode()boolean equals(Object)方法?

这可能是一个实际的工作程序和一个破碎的程序之间的差异。

对于你的情况,你希望Pair对象测试逻辑相等,因为它是一个自定义类,所以你将不得不重写和实现你自己的方法equals(Object)。您也可以覆盖hashCode(),因为在覆盖equals()时必须始终这样做。

这出色有效的Java有详细介绍,这里的章节讨论这个示例:http://java.sun.com/developer/Books/effectivejava/Chapter3.pdf

+0

是否有更好的结构来存储配对? – starcaller 2010-10-13 04:58:27

+0

甚至最差的时候,只是列出一对...假设你可以每秒获得10k对== 319999600000/10000/60/60/24 =超过一年! ____你应该重新思考你的问题,而不是数据结构。 – 2010-10-13 05:02:23

+0

如果Pair有两个Integer字段,它应该占用64位系统上的40个字节或32位系统IIRC上的24个字节。所以595MB或357MB,再加上一些更多的数组列表开销。 – naiad 2010-10-13 05:41:30

0

当数据变得太大,无法存储,唯一的办法就是使用扩展内存(HDD)。 在这里你可以分区和存储在磁盘上,每个小部分加载到内存和搜索。

或者您应该使用使用更少内存和更多处理器的算法。
1.搜索文件,搜索所有的数字,并创建一个相对的二维矩阵或下面的东西。

1 2 3 4 ... 
1 0 1 0 0 
2 0 1 0 0 
3 0 0 0 0 
... 


2.您可以对此矩阵进行排序。
3.一对一搜索文件以获得行号包含两个成对的数字。
对不起,因为我的英语不好。

相关问题