Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Adding for-loop prevents OutOfMemoryError

When I remove the for-loop I get an OutOfMemoryError. When I use for-loop I don't get any error.

Can anyone help me to understand this behavior?

public class JavaMemoryPuzzlePolite {     private final int dataSize = (int) (Runtime.getRuntime().maxMemory() * 0.6);      public void f() {         {             System.out.println(dataSize);             byte[] data = new byte[dataSize];         }         for (int i = 0; i < 1; i++) {             System.out.println("Please be so kind and release memory");         }         System.out.println(dataSize);         byte[] data2 = new byte[dataSize];     }      public static void main(String[] args) {         JavaMemoryPuzzlePolite jmp = new JavaMemoryPuzzlePolite();         jmp.f();     } } 
like image 671
snagpal Avatar asked Jul 07 '15 05:07

snagpal


People also ask

How do you prevent OutOfMemoryError?

OutOfMemoryError: Java heap space. 1) An easy way to solve OutOfMemoryError in java is to increase the maximum heap size by using JVM options "-Xmx512M", this will immediately solve your OutOfMemoryError.

What is OutOfMemoryError in exception handling?

OutOfMemoryError exception. Usually, this error is thrown when there is insufficient space to allocate an object in the Java heap. In this case, The garbage collector cannot make space available to accommodate a new object, and the heap cannot be expanded further.


1 Answers

The f() method is executed in interpreted frame. Interpreted frames behave differently than JIT-compiled frames. Here's how it looks in pseudocode without the for loop:

1. Allocate dataSize bytes of memory 2. Store it into variable slot #1 3. Allocate dataSize bytes of memory 4. Store it into variable slot #1 

So you have the OutOfMemoryError on the step #3 as the old byte[] array still resides in variable #1. However adding the for loop (actually adding an i variable) makes thing different:

1. Allocate dataSize bytes of memory 2. Store it into variable slot #1 3. Store 0 to slot #1 (thus byte[] array is now eligible for GC) 4. Do the for loop 5. Allocate dataSize bytes of memory 6. Store it into variable slot #2 

Here when you allocate the new array at step #5, the first array can already be garbage collected.

Note that JIT compiler may behave smarter and unlink the first array from the variable as it becomes unused (in your particular case it will not allocate it at all).

Also note that in your particular case the result depends on java compiler. ECJ (Eclipse compiler) is smart enough not to store the first array into variable at all as it's not used. Thus you will not get OutOfMemoryError in ECJ-compiled class even without the for loop.

For more details you can look into bytecode disassembly output provided by javap utility and see how the variable slots are reused.

like image 106
Tagir Valeev Avatar answered Sep 21 '22 15:09

Tagir Valeev