我需要将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步。只留下元素并且不缩小数组,所以当我在convert方法中插入一个庞大的数据集时,我得到了java.lang.OutOfMemoryError:超出了GC开销限制
我需要在没有任何额外记忆的情况下做到这一点。有人可以帮帮我吗?
编辑:
我正在使用ArrayList和HashMap。
答案 0 :(得分:1)
你的理论完全有可能。它需要ArrayList
一段时间来缩小用于存储引用的内部数组的大小。您可以通过使用其他List
实现来避免这种影响,例如LinkedList
但不会显示此行为,但这些实现也会产生相当大的内存开销,可能会占用您保存的空间。
话虽如此,鉴于您的数据结构,我发现ArrayList
中的一些额外引用的开销几乎不可能将您的内存需求推到顶部。我发现你更有可能创建所有类型的副本,显然相对较大(从内部数组来看),DataItem
类型的对象。如果其他人仍然引用原始DataItem
个对象,则您对remove
的调用将从列表中删除其引用,但对象本身保持活着,直到所有对它们的引用都被删除。
我建议使用类似MAT tool之类的更小的示例检查您的内存占用情况。在转化和转换之后,查看类型中有多少DataItem
个对象。如果它们增加了,我的理论是正确的,您应该通过不复制对象,而只是复制引用(如果可以)或者通过删除来避免这个问题对旧对象的附加引用。如果我的理论错了,请检查记忆的哪一部分增加最多,以确定罪魁祸首。