Java – outofmemoryerror commented out from seemingly unrelated code blocks
Can anyone explain why the program throws an outofmemoryerror when the for loop is commented out? If it is uncommented, it works normally
The exception thrown is:
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 < 10; 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(); } }
Solution
I have investigated this with many different types of code snippets that can be inserted into your comments, and the only code type that does not cause outofmemoryerror is the code that assigns a value to a local variable
This is the most meaningful explanation for me:
When you have
byte[] data = new byte[dataSize];
Bytecode instructions yes
12: newarray byte 14: astore_1
Newarray creates a new array, astore_ 1 stores a reference to it in the local variable 1
After that, the range of the variable is lost, but the bytecode does not specify anything whose value is cleared, so there is a reference to the object remaining in the stack frame This particular garbage collector believes that it can be accessed even if the code itself cannot access it
Instead, if you try to assign another local variable, such as
byte i = 1;
Then the corresponding bytecode instruction is like
15: iconst_1 16: istore_1
Where iconst_ 1 stores the value 1 on the stack, while iStore_ 1 stores the value in variable 1, which appears to be the same as the previous variable If so, you will overwrite its value, the reference to byte [] object will be lost, and then the object "becomes" eligible for garbage collection
Final proof
Compile this code with the - G option
public class Driver { private static final int dataSize = (int) (Runtime.getRuntime().maxMemory() * 0.6); public static void main(String[] args) throws InterruptedException { { System.out.println(dataSize); byte[] data = new byte[dataSize]; } byte i = 1; System.out.println(dataSize); byte[] data2 = new byte[dataSize]; } }
Then run javap - C - L driver You will see a localvariabletable like this
LocalVariableTable: Start Length Slot Name Signature 15 0 1 data [B 0 33 0 args [Ljava/lang/String; 17 16 1 i B 32 1 2 data2 [B
Where slot is astore_ 1 and iStore_ Index in 1 So you see, when you assign a new value to a local variable, you clear the reference to byte [] Even if variables have different types / names, they are stored in the same place in bytecode