Java 如果抛出两次,预分配的OutOfMemoryError如何真正实现Throwable.getStackTrace?
这是我们的后续问题 我的问题是:如果一个Java 如果抛出两次,预分配的OutOfMemoryError如何真正实现Throwable.getStackTrace?,java,out-of-memory,Java,Out Of Memory,这是我们的后续问题 我的问题是:如果一个OutOfMemoryError是预分配的(以避免OutOfMemoryError对象内存不足的情况),并且JVM必须抛出这种类型的错误两次或两次以上,那么预分配的对象如何真正实现getStackTrace方法 如果重复使用同一个对象,那么其中一个对象很可能具有无效的getStackTrace,不是吗?答案的关键在于合同: 在某些情况下,某些虚拟机可能会从堆栈跟踪中忽略一个或多个堆栈帧。在极端情况下,如果虚拟机没有与此可丢弃项相关的堆栈跟踪信息,则允许该虚
OutOfMemoryError
是预分配的(以避免OutOfMemoryError
对象内存不足的情况),并且JVM必须抛出这种类型的错误两次或两次以上,那么预分配的对象如何真正实现getStackTrace
方法
如果重复使用同一个对象,那么其中一个对象很可能具有无效的getStackTrace,不是吗?答案的关键在于合同: 在某些情况下,某些虚拟机可能会从堆栈跟踪中忽略一个或多个堆栈帧。在极端情况下,如果虚拟机没有与此可丢弃项相关的堆栈跟踪信息,则允许该虚拟机从此方法返回零长度数组 抛出的
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);
}
输出:
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)
堆栈跟踪长度=2,对象id=1743911840
堆栈跟踪长度=3,对象id=2136955031
堆栈跟踪长度=4,对象id=903470137
堆栈跟踪长度=5,对象id=1607576787
堆栈跟踪长度=0,对象id=2103957824答案的关键在于合同:
在某些情况下,某些虚拟机可能会从堆栈跟踪中忽略一个或多个堆栈帧。在极端情况下,如果虚拟机没有与此可丢弃项相关的堆栈跟踪信息,则允许该虚拟机从此方法返回零长度数组
抛出的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);
}
输出:
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)
堆栈跟踪长度=2,对象id=1743911840
堆栈跟踪长度=3,对象id=2136955031
堆栈跟踪长度=4,对象id=903470137
堆栈跟踪长度=5,对象id=1607576787
堆栈跟踪长度=0,object id=2103957824从另一个问题中可以看出,HotSpot JVM实际上会预分配OutOfMemoryErrors
,而不带任何堆栈跟踪,并且其中有许多具有预分配的空间来填充堆栈跟踪。从另一个问题中可以看出,HotSpot JVM实际上会预分配OutOfMemoryErrors
不包含任何堆栈跟踪,并且其中许多具有预先分配的空间以填充堆栈跟踪