JVM如何保证finally块的执行? [英] How does the JVM guarantee execution of the finally block?

查看:211
本文介绍了JVM如何保证finally块的执行?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这个问题的目的是为了确保JVM能够保证执行finally块(只要JVM不会崩溃,并且线程不被中断或退出)。



面试问题提示,我正在尝试了解JVM如何能够确保即使在奇怪的情况下也会执行finally块...请考虑以下代码:

  try {

int [] someArray = new int [10 ]。
int invalid = someArray [10];
}
catch(IndexOutOfBoundsException e){

throw new RuntimeException(Other Exception);
}
finally {

//关闭打开的文件或HTTP连接等
}



虽然这可能是一个奇怪的情况,尽管其他异常不是明确处理。 JVM如何处理这样的情况?



我的想法:



从我的理解和阅读中当遇到未处理的异常时,控件从当前线程(到线程的 ThreadGroup )传输。可以在 ThreadGroup 中有一些规定来检查最终需要执行的块?我唯一可以想到的其他事情可能是finally块的地址存储在某个地方。然后JVM在检测到异常时执行goto,并在finally块执行完成后返回异常。



任何人都可以澄清这个过程是如何实际发生的?

解决方案

编译这个小程序(我意识到我应该使用你的例子,但没有任何区别)

  public static void main(String [] args){
try {
Float s = Float.parseFloat(0.0327f );
} finally {
System.out.println(hello);
}
}

我使用

 > java -version 
java版本1.8.0-ea//应该为7
Java(TM)SE运行时环境(build 1.8.0-ea-b118)
Java HotSpot(TM)64位服务器虚拟机(构建25.0-b60,混合模式)

然后执行

  javac -v -c<完全限定类名称> 

获取字节码。你会看到像

  public static void main(java.lang.String []); 
标志:ACC_PUBLIC,ACC_STATIC
代码:
stack = 2,locals = 3,args_size = 1
0:ldc#2 // String 0.0327f
2:调用方式#3 //方法java / lang / Float.parseFloat:(Ljava / lang / String;)F
5:invokestatic#4 //方法java / lang / Float.valueOf:(F)Ljava / lang /浮动;
8:astore_1
9:getstatic#5 // Field java / lang / System.out:Ljava / io / PrintStream;
12:ldc#6 // String hello
14:invokevirtual#7 //方法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 //方法java / io / PrintStream.println :( Ljava / lang / String;)V
29:aload_2
30:athrow
31:return
异常表:
从目标类型
0 9 20任何
20 21 20任何
LineNumberTable:
行10:0
行12:9
行13:17
行12:20
行14:31
StackMapTable:number_of_entries = 2
frame_type = 84 / * same_locals_1_stack_item * /
stack = [class java / lang / Throwable]
frame_type = 10 / * same * /
pre>

您会注意到最终中的代码出现两次,一次 goto 和之后。您还会注意到异常表,它指定在某一行发生异常时要使用的语句。



因此,如果声明0-9之间发生任何异常,请转到第20行,然后执行终止中的所有内容,之后 goto 。如果没有异常,请执行最终,然后执行 goto ,最后跳过 code> goto



在所有情况下,您都将执行 finally block。


其他异常未被明确处理


c code code code code code code code code code $将创建将处理任何类型的 Throwable






这是一个字母代码说明的列表。


This question is aimed at how the JVM is able to guarantee the execution of a finally block (provided the JVM doesn't crash and the thread is not interrupted or exited).

Prompted by an interview question, I am trying to understand how the JVM is able to ensure a finally block is executed even in strange circumstances... Consider the following code:

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.
}


While this may be an odd circumstance, the finally block is still guaranteed to be executed despite the Other Exception not being explicitly handled. How does the JVM handle situations like this?

My Thoughts:

From what I understand and have read so far, when an unhandled exception is encountered, control is transferred from the current thread (to that thread's ThreadGroup I think). Could there be some provision in the ThreadGroup that checks for finally blocks that need executing? The only other thing I can think of is perhaps the address of the finally block is stored somewhere. Then JVM does a goto when an exception is detected and returns to the exception when the finally block has finished execution.

Can anyone clarify how this process actually happens?

解决方案

Compile this little program (I realized I should have used your example, but it makes no difference)

public static void main(String[] args) {
    try {
        Float s = Float.parseFloat("0.0327f");
    } finally {
        System.out.println("hello");
    }
}

I used

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

And then execute

javac -v -c <fully qualified class name>

to get the bytecode. You will see something like

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 */

You'll notice the code inside the finally appears twice, once before the goto and once after. You'll also notice the Exception table which specifies which statement to go to if an exception occurs at some line.

So if any exception happens between statement 0-9, go to line 20 and execute the everything inside the finally, after the goto. If no exception occurs, execute the finally and then execute the goto skipping the finally after the goto.

In all cases you will have executed the code inside the finally block.

Other Exception not being explicitly handled

With a finally block, an Exception table entry will be created that will handle any type of Throwable.


Here's a listing of the bytecode instructions.

这篇关于JVM如何保证finally块的执行?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆