外部排序在 readInt() 调用中给出 OutOfMemory

我正在使用带有合并的外部排序来对整数文件进行排序。通常对此的解决方案是使用 -Xmx 增加 JVM 的堆大小,但我想知道是否有一种方法可以在不增加堆大小的情况下改进我的代码。


抛出错误的方法是合并方法。


public static void merge(RandomAccessFile a1, RandomAccessFile a2, RandomAccessFile b1,DataOutputStream output, int start, int end) throws FileNotFoundException, IOException {

    //a1: file being read from

    //b1: file being written to


    if((int)a1.length() == 0) {

        return;

    }


    DataInputStream input_a1 = new DataInputStream(

            new BufferedInputStream(new FileInputStream(a1.getFD())));


    DataInputStream input_a2 = new DataInputStream(

            new BufferedInputStream(new FileInputStream(a2.getFD())));



    b1.seek(start); //set output pointer to start



    int mid = (start + end) /2;

    int file_length = (int)a1.length();



    //basically if second block is empty so just copy

    if (end > file_length) {

        end = file_length;

        if (end <= mid) {

            //copy from start to EOF


            int no_of_ints_left = (file_length - start)/4;

            for(int i = 1; i <= no_of_ints_left; i++) {


                output.writeInt(input_a1.readInt());

            }

            output.flush();


            return;

        }

    }



    int first_counter = start;

    int second_counter = mid;


    int x;

    int y;


    while(first_counter < mid && second_counter < end) {

        input_a1.mark(first_counter);

        input_a2.mark(second_counter);

        x = input_a1.readInt();

        y = input_a2.readInt();

        if(x < y) {

            output.writeInt(x);

            input_a2.reset();

            first_counter += 4;

        }

        else {

            output.writeInt(y);

            input_a1.reset();

            second_counter += 4;

        }

    }


导致 OutOfMemory 错误的行是 x = input_a1.readInt() 行,但我怀疑这是错误的原因。我尝试在每次调用 merge() 后调用 System.gc(),但这并没有解决问题。我还有哪些其他方法可以优化该方法以减少内存使用量?


扬帆大鱼
浏览 139回答 1
1回答

ABOUTYOU

mark用于缓冲流的代码。这将需要整个标记部分都在内存中,这可能是您的问题。RandomAccessFile可能是获得相同功能但将数据保留在磁盘上的最简单方法。内存映射java.nio是一种更复杂的技术 - 在 32 位机器上仍然会遇到问题。但是,我猜您仍然可能会遇到大文件的严重性能问题。(堆栈跟踪对于准确查看分配失败的内容很有用。可能重新分配缓冲区。尽管分析堆会告诉您实际占用内存的内容。)
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Java