The following code is causing a OutOfMemmoryError: heap space for some 3 million rows. Memory allocated to JVM is 4 GB, using 64 bit installation.
while (rs.next())
{
ArrayList<String> arrayList = new ArrayList<String>();
for (int i = 1; i <= columnCount; i++)
{
arrayList.add(rs.getString(i));
}
objOS.writeObject(arrayList);
}
The memory referenced by the ArrayList is eligible for garbage collection in each iteration of the while loop, and internally JVM calls garbage collection (System.gc()
) before throwing an OutOfMemory Error because of heap space.
So why is the exception occurring?
I agree with @Joachim.
The below suggestion was a myth
In addition, it is recommended (in good coding convention) that do not declare any object inside the loop. Instead, declare it just before the loop start and use the same reference for initialization purpose. This will ask your code to use the same reference for each iterations and cause less burden on memory release thread (i.e. Garbage collection).
The Truth
I have edited this because I feel that there may be many people who (like me before today) still believe that declaring an object inside loop could harm the memory management; which is wrong.
To demonstrate this, I have used the same code posted on stackOverflow for this.
Following is my code snippet
The result from the output is clearly shows that there is no difference in occupying/freeing the memory if you either declare the object inside or outside the loop. So it is recommended to have the declaration to as small scope as it can.
I pay my thanks to all the experts on StackOverflow (specially @Miserable Variable) for guiding me on this.
Hope this would clear your doubts too.
Is
objOS
anObjectOutputStream
?If so, then that's your problem: An
ObjectOutputStream
keeps a strong reference to every object that was ever written to it in order to avoid writing the same object twice (it will simply write a reference saying "that object that I wrote before with id x").This means that you're effectively leaking all
ArrayList
istances.You can reset that "cache" by calling
reset()
on yourObjectOutputStream
. Since you don't seem to be using that feature anyway, you could callreset()
directly after thewriteObject()
call.