How can a preallocated OutOfMemoryError truthfully

2019-07-20 17:51发布

This is a follow up question to What happens when there's insufficient memory to throw an OutOfMemoryError?

My question is the following: If an OutOfMemoryError is preallocated (to avoid the situation of having insufficient memory for the OutOfMemoryError object) and the JVM has to throw this type of error two times or more, then how can the preallocated object truthfully implement the getStackTrace method?

If the same object is reused, then one of the objects will most likely have an invalid getStackTrace, wouldn't it?

2条回答
我欲成王,谁敢阻挡
2楼-- · 2019-07-20 18:05

The key to the answer lies in the contract to Throwable.getStackTrace():

Some virtual machines may, under some circumstances, omit one or more stack frames from the stack trace. In the extreme case, a virtual machine that has no stack trace information concerning this throwable is permitted to return a zero-length array from this method.

The OutOfMemoryError thrown is in fact not necessarily a preallocated one. If it has enough memory to allocated a new OutOfMemoryError with a proper stack trace it will. But if it hasn't got memory it will use a preallocated one with no stack trace information. Such preallocated object can therefor be reused if another OutOfMemoryError needs to be thrown.


Modifying the (best) answer to the question you mentioned explains what is going on:

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);
}

Output:

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)
查看更多
Rolldiameter
3楼-- · 2019-07-20 18:12

As can be seen in this answer to the other question the HotSpot JVM will actually pre-allocate OutOfMemoryErrors without any stack trace as well as a number of them with pre-allocated space to fill in a stack trace.

查看更多
登录 后发表回答