Java序列化期间堆空间不足

问题描述 投票:20回答:2

以下代码导致OutOfMemmoryError:大约300万行的堆空间。使用64位安装,分配给JVM的内存为4 GB。

while (rs.next())
{

    ArrayList<String> arrayList = new ArrayList<String>();
    for (int i = 1; i <= columnCount; i++)
    {
        arrayList.add(rs.getString(i));
    }

    objOS.writeObject(arrayList);
}

由ArrayList引用的内存在while循环的每次迭代中都有资格进行垃圾回收,并且由于堆空间,JVM内部会在抛出OutOfMemory错误之前调用垃圾回收(System.gc())。

那么为什么发生异常?

java serialization garbage-collection heap-memory out-of-memory
2个回答
39
投票

objOSObjectOutputStream吗?

如果是这样,那就是您的问题:ObjectOutputStream会对曾经写入过的every对象保持强烈引用,以避免重复写入同一对象(它只会写一个引用,说“我之前写过的ID为[[x“)的对象。

这意味着您实际上正在泄漏

all

ArrayList项。您可以通过在reset()上调用reset()来重置该“缓存”。由于您似乎在ObjectOutputStream调用之间似乎都没有使用该缓存,因此可以在writeObject调用之后直接调用reset()

4
投票
我同意@Joachim。

下面的建议是一个神话

另外,建议(按照良好的编码惯例)不要在循环内声明任何对象。而是在循环开始之前声明它,并使用相同的引用进行初始化。这将要求您的代码在每次迭代中使用相同的引用,从而减轻内存释放线程(即垃圾回收)的负担。

真相

我之所以这样[编辑],是因为我觉得可能有很多人(像今天之前一样)仍然相信在循环内声明对象可能会损害内存管理。这是错误的。为了证明这一点,我使用了在writeObject()上发布的相同代码。以下是我的代码段stackOverflow for this输出结果清楚地表明,无论您在循环内还是循环外声明对象,占用/释放内存都没有区别。因此,建议声明的范围尽可能小。我感谢所有StackOverflow专家(特别是@Miserable变量)为我提供了指导。
希望这也会清除您的疑虑。
© www.soinside.com 2019 - 2024. All rights reserved.