Java在序列化期间没有堆空间

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

while (rs.next()) { ArrayList arrayList = new ArrayList(); for (int i = 1; i <= columnCount; i++) { arrayList.add(rs.getString(i)); } objOS.writeObject(arrayList); } 

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

那么为什么会发生exception呢?

objOSObjectOutputStream吗?

如果是这样,那么这就是你的问题:一个ObjectOutputStream保持对每个写入它的对象的强引用,以避免两次写入同一个对象(它只会写一个引用说“我之前用id x写过的那个对象” “)。

这意味着您正在有效地泄露所有 ArrayList节点。

您可以通过调用ObjectOutputStream上的reset()来重置“缓存”。 由于您似乎无论如何都不使用该function,因此可以在writeObject()调用之后直接调用reset()

我同意@Joachim。

以下建议是一个神话

此外,建议(在良好的编码约定中) 不在循环内声明任何对象 相反,在循环开始之前声明它并使用相同的引用进行初始化。 这将要求您的代码对每次迭代使用相同的引用,并减少内存释放线程(即垃圾收集)的负担。

真相
编辑过这个因为我觉得可能有很多人(像我之前一样)仍然认为在循环中声明一个对象可能会损害内存管理; 这是错的。
为了certificate这一点,我使用了stackOverflow上发布的相同代码。
以下是我的代码段

 package navsoft.advskill.test; import java.util.ArrayList; public class MemoryTest { /** * @param args */ public static void main(String[] args) { /* Total number of processors or cores available to the JVM */ System.out.println("Available processors (cores): " + Runtime.getRuntime().availableProcessors()); /* * Total amount of free memory available to the JVM */ long freeMemory = Runtime.getRuntime().freeMemory(); System.out.println("Free memory (bytes): " + freeMemory); /* * This will return Long.MAX_VALUE if there is no preset limit */ long maxMemory = Runtime.getRuntime().maxMemory(); /* * Maximum amount of memory the JVM will attempt to use */ System.out.println("Maximum memory (bytes): " + (maxMemory == Long.MAX_VALUE ? "no limit" : maxMemory)); /* * Total memory currently in use by the JVM */ System.out.println("Total memory (bytes): " + Runtime.getRuntime().totalMemory()); final int LIMIT_COUNTER = 1000000; //System.out.println("Testing Only for print..."); System.out.println("Testing for Collection inside Loop..."); //System.out.println("Testing for Collection outside Loop..."); //ArrayList arr; for (int i = 0; i < LIMIT_COUNTER; ++i) { //arr = new ArrayList(); ArrayList arr = new ArrayList(); System.out.println("" + i + ". Occupied(OldFree - currentFree): "+ (freeMemory - Runtime.getRuntime().freeMemory())); } System.out.println("Occupied At the End: "+ (freeMemory - Runtime.getRuntime().freeMemory())); System.out.println("End of Test"); } } 

输出的结果清楚地表明,如果要在循环内部或外部声明对象,则占用/释放内存没有区别。 因此,建议将声明尽可能小的范围。
我要感谢StackOverflow上的所有专家(特别是@Mimrable Variable)来指导我。

希望这也能清除你的疑虑。