Joe*_*oel 22 java jvm exception-handling exception try-catch
这个问题针对的是JVM如何能够保证finally块的执行(假设JVM没有崩溃并且线程没有被中断或退出).
在面试问题的提示下,我试图了解JVM如何确保即使在奇怪的情况下也能执行finally块...请考虑以下代码:
try{
int[] someArray = new int[10];
int invalid = someArray[10];
}
catch(IndexOutOfBoundsException e){
throw new RuntimeException("Other Exception");
}
finally{
//close open files or HTTP connections etc.
}
Run Code Online (Sandbox Code Playgroud)
虽然这可能是一个奇怪的情况,但仍然保证执行finally块,尽管没有明确处理其他异常.JVM如何处理这样的情况?
根据我的理解并且到目前为止已经读过,当遇到未处理的异常时,控制从当前线程转移到ThreadGroup我认为的那个线程.是否有一些条款ThreadGroup可以检查最终需要执行的块?我能想到的唯一另一件事可能是finally块的地址存储在某个地方.然后JVM在检测到异常时执行goto,并在finally块执行完毕后返回异常.
谁能澄清这个过程究竟是如何发生的?
Sot*_*lis 20
编译这个小程序(我意识到我应该使用你的例子,但它没有区别)
public static void main(String[] args) {
try {
Float s = Float.parseFloat("0.0327f");
} finally {
System.out.println("hello");
}
}
Run Code Online (Sandbox Code Playgroud)
我用了
>java -version
java version "1.8.0-ea" // should be same for 7
Java(TM) SE Runtime Environment (build 1.8.0-ea-b118)
Java HotSpot(TM) 64-Bit Server VM (build 25.0-b60, mixed mode)
Run Code Online (Sandbox Code Playgroud)
然后执行
javac -v -c <fully qualified class name>
Run Code Online (Sandbox Code Playgroud)
获取字节码.你会看到类似的东西
public static void main(java.lang.String[]);
flags: ACC_PUBLIC, ACC_STATIC
Code:
stack=2, locals=3, args_size=1
0: ldc #2 // String 0.0327f
2: invokestatic #3 // Method java/lang/Float.parseFloat:(Ljava/lang/String;)F
5: invokestatic #4 // Method java/lang/Float.valueOf:(F)Ljava/lang/Float;
8: astore_1
9: getstatic #5 // Field java/lang/System.out:Ljava/io/PrintStream;
12: ldc #6 // String hello
14: invokevirtual #7 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
17: goto 31
20: astore_2
21: getstatic #5 // Field java/lang/System.out:Ljava/io/PrintStream;
24: ldc #6 // String hello
26: invokevirtual #7 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
29: aload_2
30: athrow
31: return
Exception table:
from to target type
0 9 20 any
20 21 20 any
LineNumberTable:
line 10: 0
line 12: 9
line 13: 17
line 12: 20
line 14: 31
StackMapTable: number_of_entries = 2
frame_type = 84 /* same_locals_1_stack_item */
stack = [ class java/lang/Throwable ]
frame_type = 10 /* same */
Run Code Online (Sandbox Code Playgroud)
你会注意到里面finally的代码出现两次,一次出现在前面goto,一次出现之后.您还会注意到Exception table,如果在某行发生异常,则指定哪个语句.
因此,如果任何异常声明0-9之间的情况,请转到第20行并执行内部的一切finally,之后的goto.如果没有异常发生,执行finally,然后执行goto跳过finally后的goto.
在所有情况下,您都将执行finally块内的代码.
其他异常没有明确处理
使用finally块,Exception table将创建一个将处理任何类型的条目Throwable.
我相信这个博客清楚地描述了内部:
如果方法定义了try-catch或try-finally异常处理程序,那么将创建一个Exception Table.它包含每个异常处理程序或finally块的信息,包括处理程序应用的范围,正在处理的异常类型以及处理程序代码的位置.
抛出异常时,JVM在当前方法中查找匹配的处理程序,如果没有找到,则方法突然弹出当前堆栈帧,并在调用方法(新的当前帧)中重新抛出异常.如果在弹出所有帧之前未找到异常处理程序,则终止该线程.如果在最后一个非守护程序线程中抛出异常,这也可能导致JVM本身终止,例如,如果该线程是主线程.
最后,异常处理程序匹配所有类型的异常,因此每当抛出异常时总是执行.在没有抛出异常的情况下,仍然在方法结束时执行finally块,这是通过在执行return语句之前立即跳转到finally处理程序代码来实现的.
| 归档时间: |
|
| 查看次数: |
1706 次 |
| 最近记录: |