如果抛出两次,预分配的OutOfMemoryError如何真实地实现Throwable.getStackTrace?

aio*_*obe 2 java out-of-memory

这是一个后续问题,当没有足够的内存来抛出OutOfMemoryError时会发生什么?

我的问题如下:如果a OutOfMemoryError是预分配的(为了避免OutOfMemoryError对象的内存不足的情况)并且JVM必须抛出这种类型的错误两次或更多次,那么预分配对象如何真实地实现该getStackTrace方法?

如果重用同一个对象,那么其中一个对象很可能会失效getStackTrace,不是吗?

dac*_*cwe 5

答案的关键在于合同Throwable.getStackTrace():

在某些情况下,某些虚拟机可能会从堆栈跟踪中省略一个或多个堆栈帧.在极端情况下,允许没有关于此throwable的堆栈跟踪信息的虚拟机从此方法返回零长度数组.

OutOfMemoryError抛出其实并不一定是预分配一个.如果它有足够的内存来分配一个OutOfMemoryError具有适当堆栈跟踪的新内存,它将会.但如果它没有内存,它将使用预分配的没有堆栈跟踪信息.因此,如果需要抛出另一个预先分配的对象,则可以重新使用这种预分配对象OutOfMemoryError.


修改 您提到的问题的(最佳)答案解释了正在发生的事情:

private static void test(OutOfMemoryError o) {
    try {
        for (int n = 1; true; n += n) {
            int[] foo = new int[n];
        }
    } catch (OutOfMemoryError e) {
        System.out.println("Stack trace length=" + e.getStackTrace().length + 
                           ", object id=" + System.identityHashCode(e));
        if (e == o)
            System.out.println("Got the same OutOfMemoryError twice (abort)");
        else
            test(e);
    }
}

public static void main (String[] args) {
    test(null);
}
Run Code Online (Sandbox Code Playgroud)

输出:

Stack trace length=2, object id=1743911840
Stack trace length=3, object id=2136955031
Stack trace length=4, object id=903470137
Stack trace length=5, object id=1607576787
Stack trace length=0, object id=2103957824 <--- new object cannot be allocated
Stack trace length=0, object id=2103957824 <--- same object reused
Got the same OutOfMemoryError twice (abort)
Run Code Online (Sandbox Code Playgroud)