zoukankan      html  css  js  c++  java
  • JVM是如何处理异常的

    一. 异常简介

      异常是开发工作中必不可少的,它实现了程序控制流的非正常转移。异常的处理很能体现出一个程序员的编码水平,不过这一篇文章并不讲解如何在业务流中应用异常,而是介绍一下异常在JVM中的底层实现,以便你更好的认识和使用它。

      异常可分为抛出异常和捕获异常两个主要步骤。

      抛出异常可分为显示抛出和隐式抛出。显示抛出指的是在代码中显示调用throw关键字,换句话说也就是字节码指令抛出的。隐式抛出是指JVM抛出的异常,当虚拟机遇到无法继续运行的异常状态时抛出 比如数组越界异常。

      捕获异常都是显示的,需要编码,其中涉及了三个代码块:

      1)try代码块:用来标记需要异常监控的代码。

      2)catch代码块:跟在try之边,用来捕获try代码块抛出的异常。可以定义多个catch代码块捕捉不同的异常,执行时从上至下依次匹配,匹配成功不会再继续匹配,类似于if、else if。

      3)finally代码块:跟在 try 代码块和 catch 代码块之后,当执行完try或catch后会执行finally代码块。

      在程序正常执行的情况下,这段代码会在 try 代码块之后运行。否则,也就是 try 代码块触发异常的情况下,如果该异常没有被捕获,finally 代码块会直接运行,并且在运行之后重新抛出该异常。如果该异常被 catch 代码块捕获,finally 代码块则在 catch 代码块之后运行。在某些不幸的情况下,catch 代码块也触发了异常,那么 finally 代码块同样会运行,并会抛出 catch 代码块触发的异常。在某些极端不幸的情况下,finally 代码块也触发了异常,那么只好中断当前 finally 代码块的执行,并往外抛异常。

      额外要注意,如果try抛出了异常1,catch抛出了异常2,那么finally中最终捕获到的是异常2。遇到这样的情况,我们最终会丢失异常1,。Java7中提供了Suppressed 异常解决这个问题,它可以将一个异常附加到另一个异常上。

      Java中的异常都继承自Throwable类,Throwable有两个子类:Error、Exception。Error是指那些严重不可恢复的错误,如OOMError,Error是不应该捕获也无法通过代码修复的。Exception涵盖程序可能需要捕获并且处理的异常。

      Exception 有一个特殊的子类 RuntimeException,用来表示“程序虽然无法继续执行,但是还能抢救一下”的情况。前边提到的数组索引越界便是其中的一种。

      Error和RuntimeException属于非检查异常,其他的Exception属于检查异常。在Java语法中,所有检查异常都应该被try catch捕获,否则编译器会报错。这么设计是为了避免有些应该捕获的异常没有被捕获。

      异常对象的创建代价十分昂贵,JVM需要生成该异常的栈轨迹,这一操作会逐一访问当前线程的栈帧,记录各种调试信息(方法名、类名、文件名、行数)。既然异常实例的构造十分昂贵,我们是否可以缓存异常实例,在需要用到的时候直接抛出呢?从语法角度上来看,这是允许的。然而,该异常对应的栈轨迹并非 throw 语句的位置,而是新建异常的位置。

    二. JVM如何捕获异常

      在编译的字节码中,每个方法都有一个异常表。异常表每一条信息都对应着一个异常处理器,这条信息包括 from(监控起始位置) to(监控终止位置) target(target 指针则指向异常处理器的起始位置,例如 catch 代码块的起始位置)、捕获的异常类型。

      当程序触发异常时,Java 虚拟机会从上至下遍历异常表中的所有条目。当触发异常的字节码的索引值在某个异常表条目的监控范围内,Java 虚拟机会判断所抛出的异常和该条目想要捕获的异常是否匹配。如果匹配,Java 虚拟机会将控制流转移至该条目 target 指针指向的字节码。

      如果遍历完所有异常表条目,Java 虚拟机仍未匹配到异常处理器,那么它会弹出当前方法对应的 Java 栈帧,并且在调用者(caller)中重复上述操作。在最坏情况下,Java 虚拟机需要遍历当前线程 Java 栈上所有方法的异常表。

      finally 代码块的编译比较复杂。当前版本 Java 编译器的做法,是复制 finally 代码块的内容,分别放在 try-catch 代码块所有正常执行路径以及异常执行路径的出口中。这是一个取巧的方式,虽然看着low但是很简洁不易产生bug,这也是编程应有的样子。

  • 相关阅读:
    期末考试(优先队列)
    看病要排队《优先队列》
    Windows Message Queue(优先队列)
    Stones(优先队列)
    懒省事的小明(优先队列)
    产生冠军(set,map,拓扑结构三种方法)
    Web轻量级扫描工具Skipfish
    Web侦察工具HTTrack (爬取整站)
    文件上传漏洞绕过技巧
    Python爬虫之selenium的使用(八)
  • 原文地址:https://www.cnblogs.com/LTEF/p/13674410.html
Copyright © 2011-2022 走看看