【发布时间】:2015-08-30 02:14:51
【问题描述】:
我需要将 Map 转换为 2D 数组,所以我编写了这段代码,但它占用了大量内存,我不知道为什么。
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);
}
}
算法应该做什么:
- 从列表中取出最后一个元素
- 复制它。
- 从列表中删除元素
- 将副本存储到新的二维数组中
- 重复直到列表为空
这应该适用于地图中的所有列表。
问题是,第 3 步只保留元素而不缩小数组,所以当我在转换方法中插入一个巨大的数据集时,我得到 java.lang.OutOfMemoryError: GC 开销限制超出
我需要在没有任何额外内存的情况下执行此操作。有人可以帮帮我吗?
编辑:
我正在使用 ArrayList 和 HashMap。
【问题讨论】:
-
如果您删除原件,为什么需要复制
DataItem对象?只需将引用复制到结果数组中即可。请在您的情况下指定dataSet有多大(您总共有多少DataItem对象)。 -
我删除了一个我修改“数据”的内部循环。它可以是更短的向量。这对我的问题并不重要,我不想在这里混淆人们。
-
您将始终需要 一些 额外的内存用于该进程。我不知道,您为
Map和List使用了哪些集合,但是每个 类型都会在某个时候缩小大小(尽管不是立即)。HashMap和ArrayList可能会比TreeMap和LinkedList花费更长的时间,但在变化LinkedList开始时会有相当大的内存开销。我认为您的问题实际上是您的工作非常非常接近内存限制。如果你无法支付这里的开销并以某种方式逃脱它,它会在其他地方咬你。 -
我已经编辑了我使用的集合。这很奇怪,我应该有 1 Gb 的空闲空间(考虑我的数据集有 4 Gb)
-
另一件事:您确定第 3 步是您的问题吗?由于数据的主要部分似乎在那些大的
DataItem对象中,所以只有引用它们的列表才是问题所在,这真的很奇怪。您确定您没有在此处复制那些DataItem对象并且仍然在其他地方引用旧对象,所以最后您创建了 2 个数据副本?
标签: java arrays performance memory collections