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虚拟机执行时都能有一致的行为表现。

时间: 2024-08-29 15:12:47

java虚拟机规范阅读(三)异常的相关文章

java虚拟机规范阅读(一)简介

java虚拟机规范在日常工作中可以说根本用不到,但作为一个完美主义者,感觉如果进入java这个行业,对它的方方面面不去掌握的话,未免有些遗憾,我没有那些改写java语言大师们的天赋,我只能站在他们的肩膀,来掌握他们创造的技术. 闲话不多说,我会认真读java虚拟机并写下自己理解或者有用的东西,看到的.写下的.说出的才是学到的,读者可以去http://down.51cto.com/自行下载java虚拟机规范. 关于java虚拟机规范: 本规范描述的是一种抽象化的虚拟机的行为,而不是任何一种(译者注

java虚拟机规范阅读(四)Java虚拟机指令集简介

Java 虚拟机的指令由一个字节长度的.代表着某种特定操作含义的操作码(Opcode)以及跟随其后的零至多个代表此操作所需参数的操作数(Operands)所构成.虚拟机中许多指令并不包含操作数,只有一个操作码. 如果忽略异常处理,那 Java 虚拟机的解释器使用下面这个伪代码的循环即可有效地工作: do {   自动计算 PC 寄存器以及从 PC 寄存器的位置取出操作码;   if (存在操作数) 取出操作数;   执行操作码所定义的操作 } while (处理下一次循环); do { 自动计算

Java虚拟机规范阅读(二)IEEE754简介以及Java虚拟机中的浮点算法

什么是浮点数 在计算机系统的发展过程中,曾经提出过多种方法表达实数.典型的比如相对于浮点数的定点数(Fixed Point Number).在这种表达方式中,小数点固定的位于实数所有数字中间的某个位置.货币的表达就可以使用这种方式,比如 99.00 或者 00.99 可以用于表达具有四位精度(Precision),小数点后有两位的货币值.由于小数点位置固定,所以可以直接用四位数值来表达相应的数值.SQL 中的 NUMBER 数据类型就是利用定点数来定义的.还有一种提议的表达方式为有理数表达方式,

《Java虚拟机规范》阅读笔记-数据类型

<Java虚拟机规范>阅读笔记-数据类型 JVM 数据类型 1.概述 Java虚拟机的数据类型可分为两大类:原始类型(Primitive Types,也称为基本类型)和引用类型(Reference Types). Java虚拟机用不同的字节码指令来操作不同的数据类型 . 2.原始类型 原始类型是最基本的元素,用于构成复杂的引用类型.与世间万物一样,都是由最基本的化学元素组合而成. 原始类型又分为三类:数值类型(Numberic Types).布尔类型(Boolean Type).ReturnA

如何写出让java虚拟机发生内存溢出异常OutOfMemoryError的代码

程序小白在写代码的过程中,经常会不经意间写出发生内存溢出异常的代码.很多时候这类异常如何产生的都傻傻弄不清楚,如果能故意写出让jvm发生内存溢出的代码,有时候看来也并非一件容易的事.最近通过学习<深入理解java虚拟机-JVM高级特性与最佳实践>这本书,终于初步了解了一下java虚拟机的内存模型.本文通过写出使jvm发生内存溢出异常的代码来对自己的学习结果进行总结,同时也提醒自己以后写代码时候不要再跳进这个坑啦. java的内存管理是由java虚拟机自动进行管理的,并不需要程序员过多的手动干预

深入理解Java虚拟机(第三版)-14. 线程安全与锁优化

14. 线程安全与锁优化 1. 什么是线程安全? 当多个线程同时访问一个对象时,如果不用考虑这些线程在运行时环境下的调度和交替进行,也不需要进行额外的同步,或者在调用方进行任何其他的协调操作,调用这个对象的行为都可以获得正确的结果,那就称这个对象是线程安全的 2. Java语言中的线程安全 我们将Java语言下的线程安全分为以下五类:不可变.绝对线程安全.相对线程安全.线程兼容和线程对立. 1.不可变:不可变一定是线程安全的,无论是对象的方法实现还是方法的调用者,都不需要进行任何线程安全保障措施

JAVA 虚拟机深入研究(三)——Java内存区域

JAVA 虚拟机深入研究(一)--关于Java的一些历史 JAVA 虚拟机深入研究(二)--JVM虚拟机发展以及一些Java的新东西 JAVA 虚拟机深入研究(三)--Java内存区域 Java与C++之间有一堵由内存动态分配和垃圾收集技术所围成的围城,城外的人想进去,城里的人想出来. Java运行的时候会把内存分为若干个,他们各有各的用途,每块区域的创建和销毁都是相对独立的,有的跟虚拟机一起混,有的则抱着用户的大腿同生共死. 按照第七版的<Java虚拟机规范>规定,JVM所管理的内存包括以下

【深入理解JAVA虚拟机】第三部分.虚拟机执行子系统.1.类文件结构

无关性 无关性的体现有两个方面: 1.平台无关性:可在不同的操作系统和机器指令集上执行,可在不同厂商的虚拟机平台上执行. 2.语言无关性:用不同编程语言写出的代码编译生成的文件都可以运行. 实现思想: 面向接口,定义虚拟机和编译器之间的接口规范.也就是编译后文件的存储格式——字节码(ByteCode). 任意一种编程语言,只要生成符合存储格式规范的Class文件,就可以被任意虚拟机执行. Class文件结构 Class文件结构是在<Java虚拟机规范>中定义的. Class文件的存储结构类似于

java虚拟机学习(三) 内存溢出异常

java 堆溢出: 在eclipse中测试时,可以在Debug/Run中设置虚拟机参数,比如-xmx 20M 代表虚拟机堆内存大小最大值是20M,-xms是最小堆内存.然后写个死循环测试类不断在List集合中添加对象, 当堆内存超出20M ,会报OutOfMemory异常. 虚拟机栈和本地方法栈溢出: 一个线程中如果,方法的深度超过了虚拟机允许的深度 ,会报StackOverFlow异常,比如递归调用方法.这个异常容易去实现,另一种是java虚拟机栈在扩展时如果无法申请到内存,则会报OutOfM