我遇到一个问题,我在循环浏览一个过大的文件(大约2GB)。运行大约5分钟后,我遇到以下问题:OutOfMemoryError:超出GC开销限制。
我的代码如下,相对干净:
import java.io.File;
import java.io.FileNotFoundException;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Scanner;
public class Organiser {
public static void main(String[] args) throws FileNotFoundException {
ArrayList<String> lines = new ArrayList<>();
String directory = "C:\\Users\\xxx\\Desktop\\Files\\combined";
Scanner fileIn = new Scanner(new File(directory + ".txt"));
while (fileIn.hasNextLine() == true) {
lines.add(fileIn.nextLine());
System.out.println("Reading.");
System.out.println("Reading..");
System.out.println("Reading...");
}
PrintWriter out = new PrintWriter(directory + "_ordered.txt");
Collections.sort(lines);
System.out.println("Ordering...");
for (String output : lines) {
out.println(output + "\n");
}
out.close();
System.out.println("Complete - See " + directory + "_ordered.txt");
}
}
想知道如何解决这个问题?
答案 0 :(得分:2)
要对非常大的文件进行排序,您可能需要执行可以放入内存的最大量的合并排序。这就是sort
unix实用程序的功能。注意:您可以从Java运行sort
而不是自己实现它。
更简单的选择是为进程提供更多内存。您将需要大约5 GB的堆或更多。当UTF-16编码为Java时,2 GB的编码文本变成4 GB,加上其他数据结构的空间。
答案 1 :(得分:0)
不要立即阅读完整的文件,而是以大块的形式阅读。
有关一次读取字节的信息,请参阅InputSteram.read(byte[])。
示例代码:
try {
File file = new File("myFile");
FileInputStream is = new FileInputStream(file);
byte[] chunk = new byte[1024];
int chunkLen = 0;
while ((chunkLen = is.read(chunk)) != -1) {
// your code..
}
} catch (FileNotFoundException fnfE) {
// file not found, handle case
} catch (IOException ioE) {
// problem reading, handle case
}
希望这会给你一个想法。
这不是一个Java问题。您需要研究一种有效的算法,用于对尚未完全读入内存的数据进行排序。对Merge-Sort的一些改编可以达到这个目的。
看看这个:http://en.wikipedia.org/wiki/Merge_sort
和:http://en.wikipedia.org/wiki/External_sorting
这里的想法基本上是将文件分成更小的部分,对它们进行排序(使用合并排序或其他方法),然后使用合并排序合并来创建新的排序文件。
答案 2 :(得分:0)
如果您的文件包含latin-1符号,则可以保存一些内存,以UTF-8 ByteBuffer
代替String
而不是String
(import java.nio.ByteBuffer;
import java.nio.charset.StandardCharsets;
...
ArrayList<ByteBuffer> lines = new ArrayList<>();
...
while (fileIn.hasNextLine() == true) {
lines.add(ByteBuffer.wrap(fileIn.nextLine().getBytes(StandardCharsets.UTF_8)));
...
for (ByteBuffer output : lines) {
out.println(new String(output.array(), StandardCharsets.UTF_8));
}
...
来表示行。 UTF-16,仅输入latin-1可能需要2倍的内存使用量):
byte[]
与简单的ByteBuffer
数组不同{{1}}具有可比性,因此可以进行排序。
答案 3 :(得分:0)
尝试在启动程序时指定java VM选项。
如果您使用的是IDE,请转到运行配置并提供-Xmx
和-Xms
标志,其中包含排序大文件内容所需的值。将其设置为大约4GB的高值,并将字符串内容包装在UTF-8
编码ByteBuffer
而不是UTF-16
中可以提供帮助。
javac Organiser.java
java -Xms1024m -Xmx4096m Organiser
答案 4 :(得分:0)
当您看到OutOfMemoryException
时,您可以优化程序,以降低内存消耗。
一些典型的&#34;轻松获得&#34;你可以实现:
ArrayList
或Collections.sort
对大量数据进行排序:请使用TreeSet,
根据自然顺序自动对其项目进行排序。-Xmx
选项增加JVM内存。看看这篇类似的帖子: Improving speed and memory consumption when handling ArrayList with 100 million elements