我有一个带有整数的大文本文件。文件中的每一行都有两个由空格分隔的整数。文件大小为63 Mb。
Pattern p = Pattern.compile("\\s");
try (BufferedReader reader = new BufferedReader(new FileReader(filePath))) {
String line;
while ((line = reader.readLine()) != null) {
String[] tokens = p.split(line);
String s1 = new String(tokens[0]);
String s2 = new String(tokens[1]);
int startLabel = Integer.valueOf(s1) - 1;
int endLabel = Integer.valueOf(s2) - 1;
Vertex fromV = vertices.get(startLabel);
Vertex toV = vertices.get(endLabel);
Edge edge = new Edge(fromV, toV);
fromV.addEdge(edge);
toV.addEdge(edge);
edges.add(edge);
System.out.println("Edge from " + fromV.getLabel() + " to " + toV.getLabel());
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
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.lang.String.subSequence(String.java:1946)
at java.util.regex.Pattern.split(Pattern.java:1202)
at java.util.regex.Pattern.split(Pattern.java:1259)
at SCC.main(SCC.java:25)
为什么我会收到此异常?如何更改我的代码以避免它?
编辑: 我已经将堆大小增加到2048m。 什么消耗它?这也是我想知道的。
据我所知,jvm应该将内存分配给顶点列表,边缘集,缓冲读取器缓冲区和一个小字符串“line”。我不知道这个outOfMemory来自哪里。
我读过有关string.split()方法的内容。我认为这会导致内存泄漏,但我不知道该怎么办。
答案 0 :(得分:4)
首先应该尝试将文件缩小到足以使其正常工作。这将使您能够评估您遇到的问题有多大。
其次,您的问题肯定与String#split
无关,因为您一次只在一行上使用它。正在消耗堆的是Vertex
和Edge
个实例。你需要重新设计一个更小的占用空间,或者彻底检查你的算法,以便只能在内存中使用图形的一部分,其余部分在磁盘上。
P.S。只是一般的Java注释:不要写
String s1 = new String(tokens[0]);
String s2 = new String(tokens[1]);
你只需要
String s1 = tokens[0];
String s2 = tokens[1];
甚至只是直接使用tokens[0]
代替s1
,因为它很明显。
答案 1 :(得分:3)
最简单的方法:增加堆大小: 将-Xmx512m -Xms512m(甚至更多)参数添加到jvm
答案 2 :(得分:2)
使用-Xmx
JVM选项增加堆内存限制。
更多信息here。
答案 3 :(得分:2)
您收到此异常是因为您的程序在Java堆中存储了太多数据。
虽然您的异常出现在Pattern.split()方法中,但实际的罪魁祸首可能是代码中的任何大内存用户,例如您正在构建的图形。看看你提供的内容,我怀疑图形数据结构存储了大量冗余数据。您可能想要研究更节省空间的图形结构。
如果您使用的是Sun JVM,请尝试使用JVM选项-XX:+ HeapDumpOnOutOfMemoryError来创建堆转储并对任何大量内存用户进行分析,并使用该分析来优化代码。有关详细信息,请参阅Using HeapDumpOnOutOfMemoryError parameter for heap dump for JBoss。
如果这对你来说太多了,正如其他人所指出的那样,请尝试将JVM堆空间增加到程序不再崩溃的程度。
答案 4 :(得分:0)
你有异常,因为你的堆空间已经完成。尝试使用
增加堆 java -Xms512 -Xmx2048 (for example)
答案 5 :(得分:0)
当你试图解析东西时,你得到一个OOM,它只是你正在使用的方法是不可扩展的。即使增加堆可能暂时解决问题,但它不可扩展。例如,如果明天您的文件大小增加了一个数量级或数量级,那么您将回到原点。 我建议尝试分段读取文件,缓存文件的x行,读取它,清除缓存并重新执行该过程。 您可以使用ehcache或guava缓存。
答案 6 :(得分:0)
您可以更改解析字符串的方式。
try (Scanner scanner = new Scanner(new FileReader(filePath))) {
while (scanner.hasNextInt()) {
int startLabel = scanner.nextInt();
int endLabel = scanner.nextInt();
scanner.nextLine(); // discard the rest of the line.
// use start and end.
}
我怀疑内存消耗实际上是你构建的数据结构,而不是你如何读取数据,但这应该会使它更加明显。