当看似无关的代码块注释掉时OutOfMemoryError [英] OutOfMemoryError when seemingly unrelated code block commented out
问题描述
有人解释为什么当 for
循环被注释掉时,该程序会抛出 OutOfMemoryError
?如果没有注释,则运行正常。
Could someone explain why this program throws a OutOfMemoryError
when the for
loop is commented out? If it is uncommented this runs fine.
引发的异常是:
线程mainjava中的异常。 lang.OutOfMemoryError:Java堆空间
Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
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();
}
}
推荐答案
我已经使用许多不同类型的代码片段进行了调查,这些代码片段可以插入到您的注释所在的位置,并且唯一不会导致 OutOfMemoryError
的代码类型是指定一些值的代码到本地变量。
I've investigated this with many different types of code snippets that can be inserted where your comment is and the only type of code that will not cause an OutOfMemoryError
is code that assigns some value to a local variable.
这是对我来说最有意义的解释:
This is the explanation that makes the most sense to me:
当你有
byte[] data = new byte[dataSize];
12: newarray byte
14: astore_1
其中 newarray
创建一个新数组并且 astore_1
在局部变量1中存储对它的引用。
Where newarray
creates a new array and astore_1
stores a reference to it in a local variable 1.
此后,该变量的范围丢失,但是字节码没有说明它的值被清除,所以有一个对象保留在堆栈帧中。即使代码本身无法访问它,这个特定的垃圾收集器也认为它是可以访问的。
After this, the scope of that variable is lost, but the bytecode doesn't say anything about its value being cleared, so there's a reference to that object remaining in the stack frame. This specific garbage collector deems it reachable even if the code itself cannot reach it.
如果你尝试分配另一个局部变量,比如
If instead you try to assign another local variable, like
byte i = 1;
然后相应的字节代码指令类似于
then the corresponding byte code instructions are something like
15: iconst_1
16: istore_1
其中 iconst_1
将值1存储在堆栈中, istore_1
将该值存储在变量1中,这似乎是与以前相同的变量。如果是,则覆盖其值,对 byte []
对象的引用将丢失,然后该对象变为符合垃圾回收条件。
where iconst_1
stores the value 1 on the stack and istore_1
stores that value in the variable 1, which seems to be the same variable as before. If it is, then you are overwriting its value, the reference to the byte[]
object is lost, and the object then "becomes" eligible for garbage collection.
最终证明
使用 -g编译此代码
选项
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];
}
}
然后运行 javap -c -l Driver
。你会看到一个 LocalVariableTable
就像这样
and then run javap -c -l Driver
. You will see a LocalVariableTable
like so
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是 astore_1
和 istore_1
中的索引。所以你看,当你为局部变量赋值时,会清除对 byte []
的引用。即使变量具有不同的类型/名称,在字节码中,它们也存储在同一个地方。
where slot is the index in astore_1
and istore_1
. So you see, the reference to the byte[]
is cleared when you assign a new value to the local variable. Even if the variables have different types/names, in bytecode, they are stored in the same place.
这篇关于当看似无关的代码块注释掉时OutOfMemoryError的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!