好的,我在某个特定情况下遇到问题,我的程序从堆空间中得到内存不足错误。
假设我们有两个ArrayList,第一个包含许多T
个对象,第二个包含从第一个List的W
个对象创建的T
个对象。
我们以这种方式循环它(在循环之后列表:
public void funct(ArrayList<T> list)
{
ArrayList<W> list2 = new ArrayList<W>();
for (int i = 0 ; i < list.size() ; i++)
{
W temp = new W();
temp.set(list.get(i));
temp.saveToDB();
list2.add(temp);
}
// more code! from this point on the `list` is useless
}
我的代码与此代码非常相似,但是当list
包含大量对象时,我经常会从内存中获取堆空间(在for循环期间),我想解决这个问题。
我不太清楚GC
如何在java中工作,但在前面的例子中肯定有很多可能的优化。
由于在for循环后list
不再使用,我认为首先优化从for loop
更改为do loop
并在我们循环时清空list
:
public void funct(ArrayList<T> list)
{
ArrayList<W> list2 = new ArrayList<W>();
while (list.size() > 0)
{
W temp = new W();
temp.set(list.remove(0));
temp.saveToDB();
list2.add(temp);
}
// more code! from this point on the `list` is useless
}
这种修改有用吗?
如何更好地优化上述代码?以及如何防止堆空间内存错误? (不可能增加XMX
和XMS
值。
答案 0 :(得分:1)
这取决于很多事情。 W和T物体有多大? 你可以肯定做的一个优化是ArrayList list2 = new ArrayList(list.size()); 这样,您的listarray不需要多次调整其大小。 这不会有太大的差异。真正的问题可能是你的W和T物体的大小和数量。您是否考虑过使用不同的数据结构来管理较小部分的对象?
答案 1 :(得分:1)
您可以尝试设置-XX:MaxNewSize=40% of you Xmx
和-XX:NewSize=40% of you Xmx
此参数将加速GC调用,因为您的创建率很高。
如需更多帮助,请查看here
答案 2 :(得分:1)
如果您进行了一些内存分析,您会发现最大的耗尽源是W
个实例,您可以通过将它们添加到list2
来保留这些实例。 ArrayList
本身为每个包含的对象增加了一个非常小的开销(如果正确预先调整大小只有4个字节,最差情况下为8个字节),所以即使你保留list
,这也无关紧要。
如果不改变您在循环中创建的每个W
实例的非保留方法,您将无法减轻堆压力。
答案 3 :(得分:0)
您继续引用原始列表中的所有项目:
temp.set(list.get(i)) // you probably store somewhere the passed reference
如果T对象的大小很大而且你不需要它的所有字段,请尝试使用它的投影。
temp.set( extractWhatINeed( list.get(i) ) )
这将涉及创建一个字段少于T的新类(提取方法的返回类型)。
现在,当您不引用原始项目时,它们符合GC的条件(当列表本身不再被引用时)。