Reputation: 127
Why does this following code
List<Object> list = new ArrayList<>();
while (true) {
for(int i = 0; i < 1000000; i++){
list.add(new Object());
}
}
produce an out of memory error
But this code doesn't
while(true) {
List<Object> list = new ArrayList<>();
for(int i = 0; i < 1000000; i++){
list.add(new Object());
}
}
I can see that it has something to do with the list being created either inside the while loop or outside of it obviously, but I am unsure on the reason why this happens.
Upvotes: 7
Views: 1413
Reputation: 96
The only difference between the two codes is the location of List list = new ArrayList<>(); line. For the first code, ArrayList declared outside of the while loop and it keeps adding infinite numbers of objects into the one ArrayList instance so the out of memory occurs. On the other hand, the second one declares ArrayList inside of while loop so it will instantiate a new ArrayList after the each loop cycle(many ArrayList instances). By the rule of Garbage Collector in Java, the previous cycle's instances will be removed since it is no longer pointed. As a result, the GC in Java prevents the out of memory in the second case.
Upvotes: 2
Reputation:
In the first example, you create a list, add items to it and then the loop finishes. In the second example, you create a list, add things to it, then create a new List, add a bunch of things to it and repeat infinitely. Since in the first example your variable is created outside the loop, there is only 1 list to fill.
Upvotes: 2
Reputation: 14668
This question is well answered by @Eran, @TheLostMind and all, so I am not putting same point, I just want to take the opportunity make a point on how SoftReference and WeakReference helps to "delay" the out of memory exception.
Run below code with JVM arguments as -Xms64m -Xmx64m
so that you can see the results quickly.
import java.lang.ref.SoftReference;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
public class OOM {
public static void main(String[] args) {
System.out.println(new Date());
try {
scenario1(false, false); // in my box, OOM occurred with average of 2 seconds.
//scenario1(true, false); // in my box, OOM occurred average of 6 seconds.
//scenario1(false, true); // in my box, OOM occurred average of 8 seconds.
} catch (Exception e) {
} catch (Error err){
}
System.out.println(new Date());
}
private static void scenario1(boolean useSoftReference, boolean useWeakReference) {
List<Object> list = new ArrayList<>();
while (true) {
for(int i = 0; i < 1000000; i++){
if(useSoftReference){
list.add(new SoftReference<Object>(new Object()));
} else if(useWeakReference){
list.add(new WeakReference<Object>(new Object()));
} else{
list.add(new Object());
}
}
}
}
}
Upvotes: 3
Reputation: 2922
In the first scenario, the list object is declared outside the while loop, which again is running indefinitely ( as while (true )), thus it keeps on adding till it runs out of memory, while in the second one because you have declared the list inside the while, the max size is restricted to the number of iterations of the for loop.
Each time the for loop exists, the list object is reset that is new one is created to which you start adding, thus you have an upper limit. The old object is garbage collected thus clearing the JVM.
Upvotes: 3
Reputation: 394066
In the first case, you have a single ArrayList
instance and you keep adding to it new Object
instances until you run out of memory.
In the second case, you create a new ArrayList
in each iteration of the while
loop and add 1000000
Object
instances to it, which means the ArrayList
created in the previous iteration and the 1000000
Object
instances it contains can be garbage collected, since the program no longer has references to them.
Note that the second snippet can also cause out of memory error if the new Object
s are created faster than the garbage collector can release the old ones, but that depends on the JVM implementation.
Upvotes: 10
Reputation: 5911
Because when you create the list inside the while loop your previous list gets dumped and you have a new empty list. Afterwards your memory gets freed by the java garbage collector and you add 1000000 elements to the list. Then a new list gets created and everything repeats itself.
Upvotes: 3
Reputation: 36304
In your second case the list created (and where the elements are added) is going out of scope and eligible for GC. This will be GCed to make memory for the new ArrayList
. Thus for every iteration, a new ArrayList
is created and then it becomes eligible for GC (when the loop ends). Thus when memory is low, these objects will be GCed.
In the first case you are adding elements to the same ArrayList
. Nothing is being GCed.
Upvotes: 4
Reputation: 312126
In the first snippet, the list is created (and retained!) outside the loop, so you just keep endlessly adding elements to it until you consume all the available memory.
In the second snippet, each iteration of the while
loop creates a new ArrayList
object. Since you no longer hold a reference to that instance once the iteration ends, this list is eligible for garbage collection, so the old lists keep getting freed and you don't exhaust your memory.
Upvotes: 5