为什么OOME试图抓住它时会有不同的行为?

时间:2013-08-10 21:48:02

标签: java out-of-memory

我需要你们专家的一些了解

本程序不会阻止阻塞(因为Heap已满,但我想了解原因)

public class OOME_NotCatch {

    static List l = new ArrayList();
    static Long i = new Long(1);

    public static void main(String[] args) {
        try {
            while (true) {
                l.add(i);
                i++;
            }
        } catch (OutOfMemoryError e) {
            e.printStackTrace();
            System.out.println("Encountered OutOfMemoryError");
        }
    }
}
//Console : Exception in thread "main" 

但即使在获得OOME之后,下面的程序运行良好:

public class Catch_OOME_Collection {

    static List l = new ArrayList();

    public static void main(String[] args) {
        try {
            while (true) {
                l.add(new byte[1000000]);
                System.out.println("size " + l.size());
            }
        } catch (OutOfMemoryError e) {
            System.out.println("Encountered OutOfMemoryError");
            e.printStackTrace();
            System.out.println("size of list is  " + l.size());
            Iterator i = l.iterator();
            while(i.hasNext()){
                System.out.println(i.next().toString());
                i.remove();
            }
            while (true) {
                System.out.println("keep printing");
            }
        }
    }
}

在看到同样错误OOME的不同结果后,我有点困惑。请指导

3 个答案:

答案 0 :(得分:8)

我的理解是,在第一个程序中,在尝试分配一个新的Long对象时抛出OOME,该对象只占用几个字节的内存。这意味着堆已经完全填满,并且没有可用的内存来运行catch块。

在第二个程序中,当尝试分配一个100万字节的新数组时,会抛出OOME。它失败了,但这可能意味着堆仍然有999,990字节可用,这足以让catch块执行。

答案 1 :(得分:5)

两个程序都进入catch块。发生的事情是,在它设法生成并打印消息之前,它们中的任何一个都会再次耗尽内存,程序会立即收到新的OutOfMemoryError

当我尝试第一个程序时,我确实看到了catch块生成的输出,这表明一旦抛出错误,程序执行是多么不可预测。在堆栈跟踪中,我看到在尝试为ArrayList创建新的后备阵列时抛出了OOME,这意味着仍有足够的内存来运行catch块。如果在创建较小的Long对象时抛出OOME,则可能会有所不同。

值得注意的是,您无法以有意义的方式捕获OutOfMemoryError:错误可能会在非常不方便的地方抛出,导致内部数据结构处于不一致状态。在这种情况下,没有明显的不良影响,但是如果您调查了ArrayList的内部字段,您会发现其modCount字段已经增加而实际上没有修改列表。

答案 2 :(得分:0)

当分配Long或更多可能增加内部数组的大小时,第一个程序内存不足。

第二个程序在分配byte[1000000].时几乎肯定耗尽了内存。这可能比第一个程序失败的原因大得多,因此现有内存可能远没有用尽与第一种情况一样,catch块中的代码可以成功分配一些Strings等来完成它必须做的事情。