JVM中tryItOut抛出StackOverflowError时finally块执行机制探究
问题背景
Java方法代码
void tryCatchFinally() { try { tryItOut(); } catch (TestExc e) { handleExc(e); } finally { wrapItUp(); } }
对应的JVM字节码
Method void tryCatchFinally() 0 aload_0 // Beginning of try block 1 invokevirtual #4 // Method Example.tryItOut()V 4 goto 16 // Jump to finally block 7 astore_3 // Beginning of handler for TestExc; // Store thrown value in local var 3 8 aload_0 // Push this 9 aload_3 // Push thrown value 10 invokevirtual #6 // Invoke handler method: // Example.handleExc(LTestExc;)V 13 goto 16 // This goto is unnecessary, but was // generated by javac in JDK 1.0.2 16 jsr 26 // Call finally block 19 return // Return after handling TestExc 20 astore_1 // Beginning of handler for exceptions // other than TestExc, or exceptions // thrown while handling TestExc 21 jsr 26 // Call finally block 24 aload_1 // Push thrown value... 25 athrow // ...and rethrow value to the invoker 26 astore_2 // Beginning of finally block 27 aload_0 // Push this 28 invokevirtual #5 // Method Example.wrapItUp()V 31 ret 2 // Return from finally block Exception table: From To Target Type 0 4 7 Class TestExc 0 16 20 any
技术疑问
当try块中的tryItOut()方法抛出StackOverflowError时,此时内存已耗尽,JVM是如何执行finally块并完成后续流程的?
回答
1. 异常匹配与处理入口
StackOverflowError属于Error范畴,不受catch(TestExc e)的捕获,会直接匹配字节码异常表中Type为any的条目(对应目标位置20),这是JVM处理未捕获Error的标准路径。
2. 栈耗尽时的finally执行保障
JVM规范强制要求:无论try块正常完成还是因异常/Error终止,finally块必须执行(除非JVM直接崩溃)。即使触发StackOverflowError导致栈空间耗尽,JVM会先执行栈展开操作——销毁tryItOut()的栈帧,释放部分栈空间,为执行finally块腾出必要的运行资源。
具体执行流程:
- 跳转到位置20后,执行
astore_1:将StackOverflowError实例存入本地变量1(本地变量表空间在方法进入时已分配,无需额外栈空间)。 - 执行
jsr 26:跳转到finally块起始位置26,此时JVM已通过栈展开腾出了执行finally逻辑的基础栈空间。 - 进入finally块后,依次执行
astore_2(存储返回地址到本地变量2)、aload_0、invokevirtual #5调用wrapItUp()——只要wrapItUp()本身是无递归、低栈消耗的简单方法,就能顺利执行完成。 - 执行
ret 2回到jsr后的位置24,最后通过aload_1和athrow将StackOverflowError重新抛出给上层调用者。
3. 极端场景:finally块再次触发栈溢出
如果wrapItUp()内部有递归调用,或者执行时仍需大量栈空间,会在finally块中再次抛出StackOverflowError。此时JVM会终止当前方法执行,直接抛出新的Error,原有的StackOverflowError会被丢弃(成为未被记录的抑制异常)。
4. 内存耗尽的边界说明
这里的“内存耗尽”如果指堆内存耗尽(OutOfMemoryError),属于另一类场景;但针对StackOverflowError导致的栈空间耗尽,JVM通过栈展开机制保障finally块的执行,这是规范硬性要求,除非JVM本身因严重故障无法继续运行。
内容的提问来源于stack exchange,提问作者bigci1
相关产品推荐
相关产品推荐

