Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/315.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 并行合并排序时内存不足错误_Java_Multithreading_Mergesort - Fatal编程技术网

Java 并行合并排序时内存不足错误

Java 并行合并排序时内存不足错误,java,multithreading,mergesort,Java,Multithreading,Mergesort,我尝试并行化我的实现:。 我想创建尽可能多的线程,因为Java虚拟机可以提供。我想使用java.lang.Runtime确定可能的最大线程数 因此我提出了一个名为MergeThread的类: public class MergeThread implements Runnable{ public int[] list; int sIndex, eIndex; public MergeThread(int[] pArray, int pStartIndex, int p

我尝试
并行化
我的实现:。
我想创建尽可能多的线程,因为Java虚拟机可以提供。我想使用java.lang.Runtime确定可能的最大线程数

因此我提出了一个名为MergeThread的类:

public class MergeThread implements Runnable{

    public int[] list;
    int sIndex, eIndex;

    public MergeThread(int[] pArray, int pStartIndex, int pEndIndex){
        list = pArray;
        sIndex = pStartIndex;
        eIndex = pEndIndex;
    }

    public void run(){
        list = mergeSort(list, sIndex, eIndex);
    }

    /**
     * Merges two sorted int array into one new sorted array.
     * @param lhs
     * @param rhs
     * @return
     */
    private static int[] merge(int[] lhs, int[] rhs) {
        int[] result = new int[lhs.length + rhs.length];

        int leftIndex = 0;
        int rightIndex = 0;
        while(leftIndex < lhs.length && rightIndex < rhs.length) {
            if(lhs[leftIndex] <= rhs[rightIndex]) {
                result[leftIndex + rightIndex] = lhs[leftIndex];
                leftIndex++;
            } else {
                result[leftIndex + rightIndex] = rhs[rightIndex];
                rightIndex++;
            }
        }

        while(leftIndex < lhs.length) {
            result[leftIndex + rightIndex] = lhs[leftIndex];
            leftIndex++;
        }

        while(rightIndex < rhs.length) {
            result[leftIndex + rightIndex] = rhs[rightIndex];
            rightIndex++;
        }

        return result;
    }

    /**
     * Sorts an array from index <code>startIndex</code> (inclusive) to <code>endIndex</code> (exclusive).
     * @param array
     * @param startIndex
     * @param endIndex
     * @return new array that is sorted
     */
    private static int[] mergeSort(int[] array, int startIndex, int endIndex) {
        int length = endIndex - startIndex;
        if(length == 0) {
            return new int[]{};
        }
        if(length == 1) {
            return new int[]{array[startIndex]};
        }

        int halfLength = length / 2;
        //int[] sortedLeftPart = mergeSort(array, startIndex, startIndex + halfLength);
        MergeThread m1 = new MergeThread(array, startIndex, startIndex + halfLength);
        Thread t1 = new Thread(m1);
        t1.start();
        //int[] sortedRightPart = mergeSort(array, startIndex + halfLength, endIndex);
        MergeThread m2 = new MergeThread(array, startIndex + halfLength, endIndex);
        Thread t2 = new Thread(m2);
        t2.start();
        try{
        t1.join();
        t2.join();
        }catch(InterruptedException e){}
        return merge(m1.list, m2.list);     
    }
}
以及一个实际启动该过程的类

import java.util.Random;

public class Aufg2 {
    public static Random random = new Random(100);

    public static void main(String[] args) {
        int[] array = createRandomArray(10000000);

        long time = System.currentTimeMillis();

        int[] sortedArray = sort(array);

        if(sortedArray.length != array.length || !isSorted(sortedArray)) {
            System.err.println("Failed to sort given array! :-(");
            return;
        }       
        System.out.println("Success! Sorting took " + (System.currentTimeMillis() - time) + "ms.");     
    }

    /**
     * Creates a randomly filled array of given length
     * @param length
     * @return
     */
    private static int[] createRandomArray(int length) {
        int[] result = new int[length];
        for(int i = 0; i < length; i++) {
            result[i] = random.nextInt();
        }
        return result;
    }

    /**
     * Checks whether a given int array is sorted in ascending order  
     * @param array
     * @return <code>true</code> if the given int array is sorted; <code>false</code> otherwise.
     */
    private static boolean isSorted(int[] array) {
        for(int i = 1; i < array.length; i++) {
            if(array[i] < array[i-1]) {
                return false;
            }
        }
        return true;
    }   

    /**
     * Sorts a given array (ascending order)
     * @param array
     * @return
     */
    private static int[] sort(int[] array){
        //TODO: use multiple threads to speed up the sorting
        MergeThread m = new MergeThread(array, 0, array.length);

        try{

        Thread t1 = new Thread(m);
        t1.start();
        t1.join();
        }catch(InterruptedException e){

        }
        return m.list;
    }
}
但是,这种合并排序不起作用。控制台打印了大量的
java.lang.OutOfMemoryError,因为它无法创建新的本机线程

稍后,消息将更改为类似于
java heap
的内容


要使合并排序正常工作,我必须做哪些更改?如何使用java.lang.Runtime进行更改?

分治机制让您尝试创建5000000个线程,每个线程都需要默认的256KB(IIRC)堆栈内存。仍然很惊讶为什么会出现一个
OutOfMemoryError


通过使用-对池中的线程数量进行一点实验来限制线程数量,但是任何比系统中的内核数量多得多的东西都不太可能提高性能(并且可能确实会降低性能).

分治机制让您尝试创建5000000个线程,每个线程都需要默认的256KB(IIRC)堆栈内存。仍然很惊讶为什么会出现一个
OutOfMemoryError


通过使用-试验池中的线程数量来限制线程数量,但任何比系统中的内核数量多得多的东西都不太可能提高性能(实际上可能会降低性能)。

首先使用ExecutorService并在其中排队新任务,而不是创建数百万个线程(这应该可以解决第一个问题;如果创建了数百万个线程,资源迟早会耗尽)。1.5倍的内核数量通常是一个很好的猜测(通常比使用可用的内核数量得到更好的结果,但这是您必须处理的问题)


然后-如果您希望此算法在任何地方都能运行,这一点绝对重要-在合理的阈值下对叶案例使用快速排序,如果您希望阈值更低,则使用插入排序(如果使用插入排序,则叶节点大小为16左右应该可以正常工作).

首先,使用ExecutorService并在其中对新任务进行排队,而不是创建数百万个线程(这应该可以解决第一个问题;如果创建数百万个线程,资源迟早会耗尽)。通常可以猜测1.5倍的核数(通常比使用可用的内核数量提供更好的结果-但这是你必须要做的事情)


然后-如果您希望此算法在任何地方都能运行,这一点绝对重要-在合理的阈值下对叶案例使用快速排序,如果您希望阈值更低,则使用插入排序(如果使用插入排序,则叶节点大小为16左右应该可以正常工作).

让一个线程处理数组的后半部分,而调用线程处理前半部分

    int halfLength = length / 2;
    MergeThread m2 = new MergeThread(array, startIndex + halfLength, endIndex);
    Thread t2 = new Thread(m2);
    t2.start();//let new thread handle the second half
    array = mergeSort(array, startIndex, startIndex + halfLength);//do first half ourselves
    try{
    t2.join();
    }catch(InterruptedException e){}
    return merge(array, m2.list);
这会将创建的线程数量减少一半

但是快速排序要比并行化好得多,因为它不需要一个后递归步骤,该步骤允许线程(具有excecutor的可运行作业)在委派后立即返回


然后,调用方只需观察所有作业何时完成

让一个线程执行数组的后半部分,而调用线程处理前半部分

    int halfLength = length / 2;
    MergeThread m2 = new MergeThread(array, startIndex + halfLength, endIndex);
    Thread t2 = new Thread(m2);
    t2.start();//let new thread handle the second half
    array = mergeSort(array, startIndex, startIndex + halfLength);//do first half ourselves
    try{
    t2.join();
    }catch(InterruptedException e){}
    return merge(array, m2.list);
这会将创建的线程数量减少一半

但是快速排序要比并行化好得多,因为它不需要一个后递归步骤,该步骤允许线程(具有excecutor的可运行作业)在委派后立即返回


然后,调用方只需观察所有作业何时完成

将确切的堆栈跟踪复制到您的日志中,然后突出显示与该跟踪对应的代码行。顺便说一句,即使您正确实现了排序,如果您尝试并行化您将尝试创建的每个分区,也可以(NlogN)线程。除了非常小的数组之外,任何东西都会失败。线程是有限的资源。将确切的堆栈跟踪复制到日志中,然后突出显示与该跟踪相对应的代码行。顺便说一句,即使您正确实现了排序,如果您尝试并行化您将尝试创建的每个分区,也可以(NlogN)线程。除了非常小的数组之外,任何东西都会失败。线程是有限的资源。很明显,任何<内核数的东西都只会损害性能。但是使用某物>nr_内核通常可以大大提高性能。根据我的经验,很好的猜测是1.5,但这是你必须尝试的。显然,太大的数字sly也不会有什么好处。很明显,任何<核数的东西都只会损害性能。但是使用一些>nr_核的东西通常可以大大提高性能。根据我的经验,一个好的猜测是1.5,但这是你必须尝试的东西。太大的核数显然也不会有什么好处。。