JVM是如何处理异常的

上篇博客我们简单说过异常信息是存放在属性表集合中的Code属性表里,那么这篇博客就单独讲Code属性表中的exception_table。

在讲之前我们先思考两个问题?

1、为什么捕获异常会较大的性能消耗?

2、为什么finally中的代码会永远执行?

接下来会从JVM虚拟机的角度来解答这两个问题。

一、概念

1、JVM是如何捕获异常的?

1、编译而成的字节码中,每个方法都附带一个异常表

2、异常表中每一个条目代表一个异常处理器

3、触发异常时,JVM会遍历异常表,比较触发异常的字节码的索引值是否在异常处理器的from指针到to指针的范围内。

4、范围匹配后,会去比较异常类型和异常处理器中的type是否相同

5、类型匹配后,会跳转到target指针所指向的字节码(catch代码块的开始位置)

6、如果没有匹配到异常处理器,会弹出当前方法对应的Java栈帧,并对调用者重复上述操作。

2、什么是异常表?

1. 每个方法都附带一个异常表

2. 异常表中每一个条目, 就是一个异常处理器

异常表如下:

3、什么是异常处理器?其组成部分有哪些?

1、异常处理器由from指针、to指针、target指针,以及所捕获的异常类型所构成(type)。
2、这些指针的数值就是字节码的索引(bytecode index, bci),可以直接去定位字节码。
3、from指针和to指针,标识了该异常处理器所监控的返回
4、target指针,指向异常处理器的起始位置。如catch代码块的起始位置
5、type:捕获的异常类型,如Exception

4、如果在方法的异常表中没有匹配到异常处理器,会怎么样?

1、会弹出当前方法对应的Java栈帧
2、在调用者上重复异常匹配的流程。
3、最坏情况下,JVM需要编译当前线程Java栈上所有方法的异常表

二、代码演示

1、try-catch

public static void main(String[] args) {
try {
mayThrowException();
} catch (Exception e) {
e.printStackTrace();
}
}
// 对应的 Java 字节码
public static void main(java.lang.String[]);
Code:
0: invokestatic mayThrowException:()V
3: goto 11
6: astore_1
7: aload_1
8: invokevirtual java.lang.Exception.printStackTrace
11: return
Exception table:
from to target type
0 3 6 Class java/lang/Exception // 异常表条目

上面Code中的字节码自己也没有仔细研究过,我们可以具体看下面的Exception table表,来进行分析。

1、from和to: 指是try和catch之间的代码的索引位置。from=0,to=3,代表从字节索引0的位置到3(不包括3)。

2、target : 代表catch后代码运行的起始位置。

3、type : 指的是异常类型,这里是指Exception异常。

当程序触发异常时,java虚拟机会从上至下遍历异常表中的所有条目。当触发异常的字节码的索引值在某个异常表条目的监控范围内,Java 虚拟机会判断所抛出的异常

和该条目想要捕获的异常是否匹配。如果匹配,Java 虚拟机会将控制流转移至该条目target 指针指向的字节码。

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

Java 虚拟机需要遍历当前线程 Java 栈上所有方法的异常表。

2、try-catch-finally

finally 代码块的编译比较复杂。当前版本 Java 编译器的做法,是复制 finally 代码块的内容,分别放在 try-catch 代码块所有正常执行路径以及异常执行路径的出口中

代码示例

public static void XiaoXiao() {
try {
dada();
} catch (Exception e) {
e.printStackTrace();
} finally {
System.out.println("Finally");
}
}
//通过javap 反编译
public static void XiaoXiao();
Code:
0: invokestatic #3 // Method dada:()V
3: getstatic #6 // Field java/lang/System.out:Ljava/io/PrintStream;
6: ldc #7 // String Finally
8: invokevirtual #8 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
11: goto 41
14: astore_0
15: aload_0
16: invokevirtual #5 // Method java/lang/Exception.printStackTrace:()V
19: getstatic #6 // Field java/lang/System.out:Ljava/io/PrintStream;
22: ldc #7 // String Finally
24: invokevirtual #8 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
27: goto 41
30: astore_1
31: getstatic #6 // Field java/lang/System.out:Ljava/io/PrintStream;
34: ldc #7 // String Finally
36: invokevirtual #8 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
39: aload_1
40: athrow
41: return
Exception table:
from to target type
0 3 14 Class java/lang/Exception
0 3 30 any
14 19 30 any

和之前有所不同,这次

1、异常表中,有三条数据,而我们仅仅捕获了一个Exception

2、异常表的后两个item的type为any

上面的三条异常表item的意思为

1、如果0到3之间,发生了Exception类型的异常,调用14位置的异常处理者。

2、 如果0到3之间,无论发生什么异常,都调用30位置的处理者。

3、 如果14到19之间(即catch部分),不论发生什么异常,都调用30位置的处理者。

`问题`:通过上面那幅图和javap反编译代码就可以很好的解释为什么finally里面的代码永远会执行?

原因:因为当前版本Java编译器的做法,是复制finally代码块的内容,分别放到所有正常执行路径,以及异常执行路径的出口中

这三份finally代码块都放在什么位置:

第一份位于try代码后 : 若果try中代码正常执行,没有异常那么finally代码就在这里执行。

第二份位于catch代码后 : 如果try中有异常同时被catch捕获,那么finally代码就在这里执行。

第三份位于异常执行路径 : 如果如果try中有异常但没有被catch捕获,或者catch又抛异常,那么就执行最终的finally代码。



问题 :为什么捕获异常会较大的性能消耗?

因为构造异常的实例比较耗性能。这从代码层面很难理解,不过站在JVM的角度来看就简单了,因为JVM在构造异常实例时需要生成该异常的栈轨迹。这个操作会逐一访问当前

线程的栈帧,并且记录下各种调试信息,包括栈帧所指向方法的名字,方法所在的类名、文件名,以及在代码中的第几行触发该异常等信息。虽然具体不清楚JVM的实现细节,但

是看描述这件事情也是比较费时费力的。

参考

深入拆解 Java 虚拟机(郑雨迪)

只要自己变优秀了,其他的事情才会跟着好起来(少将7)

【JVM虚拟机】(9)-- JVM是如何处理异常的的更多相关文章

  1. 深入理解JVM虚拟机11:Java内存异常原理与实践

    本文转自互联网,侵删 本系列文章将整理到我在GitHub上的<Java面试指南>仓库,更多精彩内容请到我的仓库里查看 https://github.com/h2pl/Java-Tutori ...

  2. JVM是如何处理异常的

    JVM处理异常 异常处理的两大组成要素是抛出异常和捕获异常.这两大要素共同实现程序控制流的非正常转移. 抛出异常可分为显式和隐式两种.显式抛异常的主体是应用程序,指的是在程序中使用throw关键字,手 ...

  3. [深入理解JVM虚拟机]第2章-Java内存区域与内存溢出异常

    2.0引-Java内存区域中,栈内存和堆内存分别装什么,为什么? 栈:解决程序的运行问题,即程序如何执行,或者说如何处理数据. 堆:解决的是数据存储的问题,即数据怎么放,放在哪儿. 参考链接https ...

  4. JVM 字节码(三)异常在字节码中的处理(catch 和 throws)

    JVM 字节码(三)异常在字节码中的处理(catch 和 throws) 在 ClassFile 中到底是如何处理异常的呢? 一.代码块异常 catch catch 中的异常代码块在异常是如何处理的呢 ...

  5. [转帖]Java虚拟机(JVM)体系结构概述及各种性能参数优化总结

    Java虚拟机(JVM)体系结构概述及各种性能参数优化总结 2014年09月11日 23:05:27 zhongwen7710 阅读数 1437 标签: JVM调优jvm 更多 个人分类: Java知 ...

  6. JVM虚拟机结构

    JVM的主要结构如下图所示,图片引用自舒の随想日记. 方法区和堆由所有线程共享,其他区域都是线程私有的 程序计数器(Program Counter Register) 类似于PC寄存器,是一块较小的内 ...

  7. JVM内存区域与内存溢出异常

    Java虚拟机在执行java程序时会把它所管理的内存会分为若干个不同的数据区域,不同的区域在内存不足时会抛出不同的异常. >>运行时数据区域的划分 (1)程序计数器程序计数器(Progra ...

  8. java虚拟机学习-JVM内存管理:深入垃圾收集器与内存分配策略(4)

    Java与C++之间有一堵由内存动态分配和垃圾收集技术所围成的高墙,墙外面的人想进去,墙里面的人却想出来. 概述: 说起垃圾收集(Garbage Collection,下文简称GC),大部分人都把这项 ...

  9. java虚拟机学习-JVM内存管理:深入Java内存区域与OOM(3)

    概述 Java与C++之间有一堵由内存动态分配和垃圾收集技术所围成的高墙,墙外面的人想进去,墙里面的人却想出来. 对于从事C.C++程序开发的开发人员来说,在内存管理领域,他们即是拥有最高权力的皇帝又 ...

随机推荐

  1. php实现点击文字提交表单并传递数据至下一个页面

    <?php $id="4";//等会要把这个数据传到第二个页面 ?> <?php echo "<li>"; echo " ...

  2. c++11线程池

    #pragma once #include <future> #include <vector> #include <atomic> #include <qu ...

  3. 使用Myeclipse2015构建SpringMVC项目

    1.新建web project 2.右键项目,给项目添加spring框架如图,不需要勾选任何一个选项. 3.在WebRoot/WEB-INF目录下添加web.xml内容如下: <?xml ver ...

  4. 让程序跳转到绝对地址0x100000去执行

    网上比较火的一个题,让程序跳转到绝对地址去执行 :可以的实现方式为: ( (void(*)())0x4110e6)(); (*(void(*)())0x4110e6)(); (*((void(*)() ...

  5. 洛谷 P2764 解题报告

    P2764 最小路径覆盖问题 问题描述: 给定有向图\(G=(V,E)\).设\(P\) 是\(G\) 的一个简单路(顶点不相交)的集合.如果\(V\) 中每个顶点恰好在\(P\) 的一条路上,则称\ ...

  6. Jupyter-notebook 导出时不显示Input[]代码

    参考: https://stackoverflow.com/questions/34818723/export-notebook-to-pdf-without-code    1. 第一个方式是直接在 ...

  7. 初识函数库libpcap

    由于工作上的需要,最近简单学习了抓包函数库libpcap,顺便记下笔记,方便以后查看 一.libpcap简介    libpcap(Packet Capture Library),即数据包捕获函数库, ...

  8. 【转】利用 force index优化sql语句性能

    今天写了一个统计sql,在一个近亿条数据的表上执行,200s都查不出结果.SQL如下: select customer,count(1) c from upv_** where created bet ...

  9. MonolithFirst

    As I hear stories about teams using a microservices architecture, I've noticed a common pattern. Alm ...

  10. HTTP协议(一)

    http协议 协议:是一种规则或者规定 tcp/ip协议:规则了tcp客户端与tcp服务器数据的通讯格式 1.知识点是什么:http协议 2.知识点有什么:规定浏览器与服务器(tcp服务器)之间的数据 ...