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

Lea*_*ner 5 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" 
Run Code Online (Sandbox Code Playgroud)

但即使在获得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");
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

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

JB *_*zet 8

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

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


Jon*_*oni 5

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

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

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