Java 合并排序创建内存堆

Java 合并排序创建内存堆,java,algorithm,methods,merge,heap,Java,Algorithm,Methods,Merge,Heap,我编写了这个合并排序,它允许用户只通过传递两个参数(ArrayList和Comparator)来调用它: 但我有一个错误: Exception in thread "main" java.lang.OutOfMemoryError: Java heap space at java.util.Arrays.copyOf(Arrays.java:3332) at java.lang.AbstractStringBuilder.ensureCapacityInternal(Abstra

我编写了这个合并排序,它允许用户只通过传递两个参数(ArrayList和Comparator)来调用它:

但我有一个错误:

Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
    at java.util.Arrays.copyOf(Arrays.java:3332)
    at java.lang.AbstractStringBuilder.ensureCapacityInternal(AbstractStringBuilder.java:124)
    at java.lang.AbstractStringBuilder.append(AbstractStringBuilder.java:448)
    at java.lang.StringBuilder.append(StringBuilder.java:136)
    at java.util.Arrays.toString(Arrays.java:4574)
如何改进合并排序?临时数组列表是错误的主要原因吗?因为这个错误发生在我尝试订购数百万数据时。使用2-3个元素,它可以工作。 编辑:这是我的算法的第一个版本,没有支持方法,我只需要做两个参数

public static < T > void sort(ArrayList < T > array, Comparator < T > c, int low, int high) {
    if (low < high) {
      int mid = low + (high - low) / 2;
      sort(array, c, low, mid);
      sort(array, c, mid + 1, high);
      merge(array, c, low, mid, high);
    }
  } 

@SuppressWarnings("unchecked")
  public static <T> void merge(ArrayList<T> array, Comparator<T> c, int p, int mid, int q) {
    Object[] tmp = new Object[q-p+1]; 
    int i = p;
    int j = mid+1;
    int k = 0;
    while (i <= mid && j <= q) {
        if (c.compare(array.get(i), array.get(j))<0)
          tmp[k] = array.get(i++);
        else
          tmp[k] = array.get(j++);
        k++;
    }
    if (i <= mid && j > q) {
        while (i <= mid) 
          tmp[k++] = array.get(i++);
    } else {
        while (j <= q)
          tmp[k++] = array.get(j++);
    }
    for (k = 0; k < tmp.length; k++)
      array.set(k+p, (T)tmp[k]);
  }
publicstaticvoid排序(ArrayListarray,Comparatorc,int-low,int-high){
如果(低<高){
int mid=低+(高-低)/2;
排序(数组、c、低、中);
排序(数组、c、中+1、高);
合并(数组、c、低、中、高);
}
} 
@抑制警告(“未选中”)
公共静态无效合并(ArrayList数组、比较器c、int p、int mid、int q){
Object[]tmp=新对象[q-p+1];
int i=p;
int j=mid+1;
int k=0;

而(i有两种解决问题的方法:

增加可用内存:正如Turing85所提到的,使用VM选项-Xmx2048m以分配2GB的内存来运行java

减少使用的内存:使用Long和Double等基本类型的ArrayList使用的内存是使用Long/Double等基本类型的等效数组的4倍(在我的简单实验中)

ArrayList<Long> instead of long[]
ArrayList而不是long[]

由于以下几个原因,也会使代码运行速度显著降低(如果您打算对非基本类型使用合并排序,您可能会看到性能提高,但内存增加不会如此显著)

它最终是关于一些堆内存。我怀疑JVM堆内存足够大,可以容纳一个数据集副本,但不能容纳两个。您可以通过使用
java-Xmx2048m…
启动程序来增加堆大小(在本例中,您为VM提供了2GB的堆内存)。还请记住,每个递归算法最终都会被怀疑为
StackOverflowException
s,因为AoT-和hotspot编译器都没有部署尾部调用优化。在我的第一个版本中,我将临时ArrayList声明到合并函数中,它即使在2000万整数上也能正常工作lem是,现在我需要将声明移到sort方法中,我认为问题是由此引起的。递归不是最好的选择,因为这是“一堆”数据……核心问题是:不能为数组(列表)分配超过
2^31-“几个”
元素
public static < T > void sort(ArrayList < T > array, Comparator < T > c, int low, int high) {
    if (low < high) {
      int mid = low + (high - low) / 2;
      sort(array, c, low, mid);
      sort(array, c, mid + 1, high);
      merge(array, c, low, mid, high);
    }
  } 

@SuppressWarnings("unchecked")
  public static <T> void merge(ArrayList<T> array, Comparator<T> c, int p, int mid, int q) {
    Object[] tmp = new Object[q-p+1]; 
    int i = p;
    int j = mid+1;
    int k = 0;
    while (i <= mid && j <= q) {
        if (c.compare(array.get(i), array.get(j))<0)
          tmp[k] = array.get(i++);
        else
          tmp[k] = array.get(j++);
        k++;
    }
    if (i <= mid && j > q) {
        while (i <= mid) 
          tmp[k++] = array.get(i++);
    } else {
        while (j <= q)
          tmp[k++] = array.get(j++);
    }
    for (k = 0; k < tmp.length; k++)
      array.set(k+p, (T)tmp[k]);
  }
ArrayList<Long> instead of long[]