首页 > 代码库 > java虚拟机规范阅读(三)异常

java虚拟机规范阅读(三)异常


    Java虚拟机里面的异常使用Throwable或其子类的实例来表示,抛异常的本质实际上是程序控制权的一种即时的、非局部(Nonlocal)的转换——从异常抛出的地方转换至处理异常的地方。

绝大多数的异常的产生都是由于当前线程执行的某个操作所导致的,这种可以称为是同步的异常。与之相对的,异步异常是指在程序的其他任意地方进行的动作而导致的异常。Java虚拟机中异常的出现总是由下面三种原因之一导致的:

1.虚拟机同步检测到程序发生了非正常的执行情况,这时异常将会紧接着在发生非正常执行情况的字节码指令之后抛出。例如:

  • 字节码指令所蕴含的操作违反了Java语言的语义,如访问一个超出数组边界范围的元素。

  • 类在加载或者链接时出现错误。

  • 使用某些资源的时候产生资源限制,例如使用了太多的内存。

2.athrow字节码指令被执行。

3.由于以下原因,导致了异步异常的出现:

  • 调用了Thread或者ThreadGroup的stop方法。

  • Java虚拟机实现的内部程序错误。

    当某条线程调用了stop方法时,将会影响到其他的线程,或者在线程组中的所有线程。这时候其他线程中出现的异常就是异步异常,因为这些异常可能出现在程序执行过程的任何位置。虚拟机的内部异常也被认为是一种异步异常

    《Java虚拟机规范》允许在异步异常被抛出时额外执行一小段有限的代码,允许代码优化器在不违反Java语言语义的前提下检测并把这些异常在可处理它们的地方抛出①。

    抛出异常的动作在Java虚拟机之中是一种被精确定义的程序控制权转移过程,当异常抛出、程序控制权发生转移的那一刻,所有在异常抛出的位置之前的字节码指令所产生的影响②都应当是可以被观察到的,而在异常抛出的位置之后的字节码指令,则应当是没有被执行过的。如果虚拟机执行的代码是被优化后的代码③,有一些在异常出现位置之后的代码可能已经被执行了,那这些优化过的代码必须保证被它们提前执行所产生的影响对用户程序来说都是不可见的。

    由Java虚拟机执行的每一个方法都会配有零至多个异常处理器(Exception Handlers),异常处理器描述了其在方法代码中的有效作用范围(通过字节码偏移量范围来描述)、能处理的异常类型以及处理异常的代码所在的位置。要判断某个异常处理器是否可以处理某个具体的异常,需要同时检查异常出现的位置是否在异常处理的有效作用范围内并且出现的异常是否异常处理器声明可以处理的异常类型或其子类型两个条件。当有异常被抛出时,Java虚拟机搜索当前方法的包含的各个异常处理器,如果能找到可以处理该异常的异常处理器,则将代码控制权转向到异常处理器中描述的处理异常的分支之中。

    搜索异常处理器时的搜索顺序是很关键的,在Class文件里面,每个方法的异常处理器都存储在一个表中。在运行时,当有异常出现之后,Java虚拟机就按照Class文件中的异常处理器表描述异常处理器的先后顺序,从前至后进行搜索。

    需要注意,Java虚拟机本身不会对方法的对异常处理器表做排序或者其他方式的强制处理,所以Java语言中对异常处理的语义,实际上是通过编译器适当安排异常处理器在表中的顺序来协助完成的。在Class文件中定义了明确的异常处理器查找顺序,才能保证无论Class文件是通过何种途径产生的,Java虚拟机执行时都能有一致的行为表现。

本文出自 “进击的程序猿” 博客,请务必保留此出处http://zangyanan.blog.51cto.com/11610700/1855720

java虚拟机规范阅读(三)异常