当看似无关的代码块注释掉时OutOfMemoryError [英] OutOfMemoryError when seemingly unrelated code block commented out

查看:122
本文介绍了当看似无关的代码块注释掉时OutOfMemoryError的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

有人解释为什么当 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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆