循环遍历大文件时的内存处理 - Java

时间:2015-10-05 10:36:28

标签: 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.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");
    }
}

想知道如何解决这个问题?

5 个答案:

答案 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而不是Stringimport 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;你可以实现:

  • 请勿使用ArrayListCollections.sort对大量数据进行排序:请使用TreeSet,根据自然顺序自动对其项目进行排序。
  • 如果这还不够,请通过-Xmx选项增加JVM内存。

看看这篇类似的帖子: Improving speed and memory consumption when handling ArrayList with 100 million elements