《深入理解JVM》9-jvm是如何处理异常的

上一节总结了方法调用,在类信息中的方法表中会标记目标方法的地址信息,这个地址信息一开始是符号引用,比如(类名+方法名+参数+返回参数)符号。在运行时必须要解析为实际的内存地址,那么这个过程是分为动态绑定和静态绑定,动态绑定也可以根据单态缓存来提高性能。这一节我们来了解一下异常处理的流程。

jvm的异常体系

Error:特别严重且无法修复的异常

Exception:可以挽救的异常

  • try-catch:在方法执行到RuntimeException时,如果有异常处理代码(try-catch)时就会查看是否catch的异常类型匹配,如果匹配则执行catch代码,不匹配直接弹出栈帧,访问调用方法的try-catch。栈帧遍历完毕。
  • finally: 在try-catch的后面如果有finally,则在当前栈帧弹出之前,执行finally的代码,即几种情况,
  1. 无异常发生,则在try代码段之后执行,
  2. 有异常发生,则在catch方法代码段执行之后执行finally代码。
  3. catch代码段执行异常,则执行finally的代码,并抛出catch代码的异常,意味着要覆盖try代码的异常
  4. finally代码执行异常,继续抛出异常

查看例子:

class Demo{
    
       public void sayHi(){
        try{
            //正常业务处理
            sout("heihei");
        }catch(NoSuchMethodException e){
            //处理异常
            handleException(e);
        }finally{
            //关闭资源
            closeResource();
        }

    }

}

在代码中有try catch finally三个部分。但是经过编译器之后,jvm会重新排列上面的代码,

Classfile /Users/david/Desktop/techfile/demo/eurekas/clients/src/test/java/Father.class
  Last modified 2020-10-15; size 710 bytes
  MD5 checksum 31051ef6ce716bf8e8cd4e884013000e
  Compiled from "Father.java"
public class Father
  minor version: 0
  major version: 52
  flags: ACC_PUBLIC, ACC_SUPER
Constant pool:
   #1 = Methodref          #8.#25         // java/lang/Object."<init>":()V
   #2 = String             #26            // heihei
   #3 = Methodref          #7.#27         // Father.sout:(Ljava/lang/String;)V
   #4 = Methodref          #7.#28         // Father.closeResource:()V
   #5 = Class              #29            // java/lang/NoSuchMethodException
   #6 = Methodref          #7.#30         // Father.handleException:(Ljava/lang/NoSuchMethodException;)V
   #7 = Class              #31            // Father
   #8 = Class              #32            // java/lang/Object
   #9 = Utf8               <init>
  #10 = Utf8               ()V
  #11 = Utf8               Code
  #12 = Utf8               LineNumberTable
  #13 = Utf8               sayHi
  #14 = Utf8               StackMapTable
  #15 = Class              #29            // java/lang/NoSuchMethodException
  #16 = Class              #33            // java/lang/Throwable
  #17 = Utf8               closeResource
  #18 = Utf8               handleException
  #19 = Utf8               (Ljava/lang/NoSuchMethodException;)V
  #20 = Utf8               sout
  #21 = Utf8               (Ljava/lang/String;)V
  #22 = Utf8               Exceptions
  #23 = Utf8               SourceFile
  #24 = Utf8               Father.java
  #25 = NameAndType        #9:#10         // "<init>":()V
  #26 = Utf8               heihei
  #27 = NameAndType        #20:#21        // sout:(Ljava/lang/String;)V
  #28 = NameAndType        #17:#10        // closeResource:()V
  #29 = Utf8               java/lang/NoSuchMethodException
  #30 = NameAndType        #18:#19        // handleException:(Ljava/lang/NoSuchMethodException;)V
  #31 = Utf8               Father
  #32 = Utf8               java/lang/Object
  #33 = Utf8               java/lang/Throwable
{
  public Father();
    descriptor: ()V
    flags: ACC_PUBLIC
    Code:
      stack=1, locals=1, args_size=1
         0: aload_0
         1: invokespecial #1                  // Method java/lang/Object."<init>":()V
         4: return
      LineNumberTable:
        line 7: 0

  public void sayHi();
    descriptor: ()V
    flags: ACC_PUBLIC
    Code:
      stack=2, locals=3, args_size=1
         0: aload_0
         1: ldc           #2                  // String heihei
         3: invokespecial #3                  // Method sout:(Ljava/lang/String;)V
         6: aload_0
         7: invokespecial #4                  // Method closeResource:()V
        10: goto          33
        13: astore_1
        14: aload_0
        15: aload_1
        16: invokespecial #6                  // Method handleException:(Ljava/lang/NoSuchMethodException;)V
        19: aload_0
        20: invokespecial #4                  // Method closeResource:()V
        23: goto          33
        26: astore_2
        27: aload_0
        28: invokespecial #4                  // Method closeResource:()V
        31: aload_2
        32: athrow
        33: return
      Exception table:
         from    to  target type
             0     6    13   Class java/lang/NoSuchMethodException
             0     6    26   any
            13    19    26   any
      LineNumberTable:
        line 12: 0
        line 18: 6
        line 19: 10
        line 13: 13
        line 15: 14
        line 18: 19
        line 19: 23
        line 18: 26
        line 19: 31
        line 21: 33
      StackMapTable: number_of_entries = 3
        frame_type = 77 /* same_locals_1_stack_item */
          stack = [ class java/lang/NoSuchMethodException ]
        frame_type = 76 /* same_locals_1_stack_item */
          stack = [ class java/lang/Throwable ]
        frame_type = 6 /* same */
}
SourceFile: "Father.java"

jvm会在操作命令后面增加异常处理表,

      Exception table:
         from    to  target type
             0     6    13   Class java/lang/NoSuchMethodException
             0     6    26   any
            13    19    26   any

上面的字节码表明需要监控sayHi方法中code的执行条数,0-6之间如果发生NoSuchMethodException异常就到target指向的目录执行代码。0-6还监控了any代表的任何异常,这是finally的功劳

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值