2015-06-14 42 views
1

我需要地图转换成二维数组,所以我写了这段代码,但它吃大量的内存,我想不通为什么。转换集合数组没有额外的内存

private DataItem[][] convertDataToArrays(boolean[] filter, 
             Map<Integer, List<T>> dataSet)       
     double[] data = new double[sizeOfNewVector]; 
     DataItem[][] reducedData = new DataItem[dataSet.size()][]; 
     for (int i = dataSet.size() - 1; i >= 0; i--) { 
      reducedData[i] = new DataItem[dataSet.get(i).size()]; 
      for (int j = reducedData[i].length - 1; j >= 0; j--) { 
       reducedData[i][(reducedData[i].length - 1) - j] = new DataItem(data); 
       dataSet.get(i).remove(j); 
      } 
      dataSet.remove(i); 
     } 
     return reducedData; 

这里的DataItem类:

public class DataItem { 

    public double[] data; 

    public DataItem(double[] data) { 
     this.data = new double[data.length]; 
     System.arraycopy(data, 0, this.data, 0, data.length); 
    } 
} 

算法应该做的:

  1. 采取最后一个元素从列表
  2. 复制。
  3. 从列表中删除元素
  4. 店复制到新的二维数组
  5. 重复,直到列表为空

这应该在地图中的所有名单。

问题是,步骤3见好就收元素,且不收缩阵列,所以当我插入转换方法,一个巨大的数据集,我有java.lang.OutOfMemoryError:GC开销超过限制

我需要这样做,没有任何额外的内存。任何人都可以帮助我吗?

编辑:

我正在使用ArrayList和HashMap。

+1

为什么你需要复制'DataItem'对象,如果你删除原件?只需将引用复制到结果数组中即可。请指定你的情况下'dataSet'有多大(大概有多少''DataItem'对象总共有)。 –

+0

我已经删除了一个修改“数据”的内部循环。它可以是更短的矢量。这对我的问题并不重要,我不想在这里混淆人。 –

+0

您将永远需要*一些*额外的存储空间。我不知道,你用于'Map'和'List'的哪个集合,但是*每个*类型都会在某个时候缩小尺寸(尽管不是立即)。 'HashMap'和'ArrayList'可能会比我们说的'TreeMap'和'LinkedList'花费更长的时间,但是改变'LinkedList'具有相当大的内存开销。我认为你的问题确实在于你的工作非常非常接近内存限制。如果你不能在这里支付这个开销并以某种方式逃避,它会把你咬到别的地方。 – mastov

回答

1

你的理论是完全可能的。它确实需要ArrayList来缩小用于存储引用的内部数组的大小。您可避免影响使用另一种List实现像LinkedList,这并不表明这种行为,但这些也有相当大的内存开销,可能吃起来你节省的空间。

这就是说,鉴于你的数据结构,我发现它不太可能只是在ArrayList的一些额外的参考开销推动你的内存需求。我发现你更有可能创建所有你的显然相对较大的副本(根据内部数组判断)DataItem类型的对象。如果其他人仍然有原来的DataItem对象的引用,你的remove的通话将从列表中删除其引用,但对象本身活路,直到所有对它们的引用被删除。

我建议你检查你的内存占用量,与实际工作,使用类似的MAT tool一个小例子。见类型的多少对象DataItem你有之前转换后。如果他们增加了,我的理论是正确的,你应该或者不复制对象避免这样的问题,但只是他们引用(如果可以的话),或者通过摆脱对旧物的附加引用。如果我的理论是错误的,请检查哪部分内存增加最多以识别罪魁祸首。