在大文件中循环时内存不足处理-Java
我遇到了一个问题,我在一个过大(大约2gb)的文件中循环。运行大约5分钟后,我发现以下问题:OutOfMemoryError:超出了GC开销限制 我的代码如下,比较干净:在大文件中循环时内存不足处理-Java,java,sorting,memory-management,java.util.scanner,file-handling,Java,Sorting,Memory Management,Java.util.scanner,File Handling,我遇到了一个问题,我在一个过大(大约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.Sc
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");
}
}
导入java.io.File;
导入java.io.FileNotFoundException;
导入java.io.PrintWriter;
导入java.util.ArrayList;
导入java.util.Collections;
导入java.util.Scanner;
公开课组织者{
公共静态void main(字符串[]args)引发FileNotFoundException{
ArrayList行=新的ArrayList();
String directory=“C:\\Users\\xxx\\Desktop\\Files\\combined”;
Scanner fileIn=new Scanner(新文件(目录+“.txt”);
while(fileIn.hasNextLine()==true){
line.add(fileIn.nextLine());
System.out.println(“读取”);
System.out.println(“读取…”);
System.out.println(“读取…”);
}
PrintWriter out=新的PrintWriter(目录+“_ordered.txt”);
集合。排序(行);
System.out.println(“订购…”);
for(字符串输出:行){
out.println(输出+“\n”);
}
out.close();
System.out.println(“完成-请参阅“+directory+”_ordered.txt”);
}
}
想知道我该如何解决这个问题吗?要对非常大的文件进行排序,您可能需要执行一个合并排序,该排序可以容纳内存中的最大数量。这就是
排序
unix实用程序的工作方式。注意:您可以从Java运行sort
,而不是自己实现它
一个更简单的选择是为进程提供更多内存。您将需要大约5 GB或更多的堆。当UTF-16像Java一样编码时,2 GB的编码文本将变成4 GB,并为数据结构的其余部分留出空间。不要一次读取完整的文件,而是分块读取 有关一次读取字节的信息,请参阅 示例代码:
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的问题。您需要研究一种有效的算法来对未完全读入内存的数据进行排序。对合并排序进行一些调整可以实现这一点
看看这个:
以及:
基本上,这里的想法是将文件分成更小的部分,对它们进行排序(使用合并排序或其他方法),然后使用“合并自合并排序”创建新的已排序文件。如果您的文件包含拉丁-1符号,您可以节省一些内存,将行存储在UTF-8
ByteBuffer中,而不是String
(String
以UTF-16表示,仅拉丁语-1输入可能占用2倍的内存):
导入java.nio.ByteBuffer;
导入java.nio.charset.StandardCharset;
...
ArrayList行=新的ArrayList();
...
while(fileIn.hasNextLine()==true){
add(ByteBuffer.wrap(fileIn.nextLine().getBytes(StandardCharsets.UTF_8));
...
for(字节缓冲输出:行){
println(新字符串(output.array(),StandardCharsets.UTF_8));
}
...
与简单的byte[]不同,
数组ByteBuffer
具有可比性,因此可以进行排序。在启动程序时尝试指定java VM选项。
如果您使用的是IDE,请转到运行配置,并提供-Xmx
和-Xms
标志,其中包含排序大文件内容所需的值。将其设置为大约4GB的高值,并将字符串内容包装为UTF-8
编码的字节缓冲而不是UTF-16
可以救命啊
javac Organiser.java
java -Xms1024m -Xmx4096m Organiser
当您看到一个OutOfMemoryException
,是时候优化您的程序以降低内存消耗了
您可以实现的一些典型“轻松收获”:
- 不要使用
ArrayList
或Collections.sort
对大量数据进行排序:而是使用TreeSet,
自动按照自然顺序对其项进行排序
- 如果这还不够,请通过
-Xmx
选项增加JVM内存
看看这篇类似的帖子:
要么保留较小的文件,要么调整分配的内存。您正在将所有行添加到一个列表中,因此RAM,然后再对它们进行排序,这会导致OutOfMemoryError
。您唯一的选择是在将它们添加到\u ordered.txt
时对它们进行排序。不要累积列表。请阅读该行,然后重试proceed@ravindra那个这将是我的答案,但OP需要对行进行排序。to希望对输入文件的行进行排序。
javac Organiser.java
java -Xms1024m -Xmx4096m Organiser