异常表
每一个try语句块catch的异常都与异常表中的一项相对应,异常表中的每一项都包括:
- 起点
-
终点,始终把catch异常位置的pc指针偏移量的最大值大1
-
处理异常时跳转到的字节码序列中的pc指针偏移量
-
被catch的异常类的常量池索引
例如:
public class Test {
public static void main(String[] args) {
try {
Class.forName("java.lang.String");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
用javap –c查看字节码如下:
Compiled from "Test.java"
public class Test extends java.lang.Object{
public Test();
Code:
0: aload_0
1: invokespecial #1; //Method java/lang/Object."<init>":()V
4: return
public static void main(java.lang.String[]);
Code:
0: ldc #2; //String java.lang.String
2: invokestatic #3; //Method java/lang/Class.forName:(Ljava/lang/String;)Ljava/lang/Class;
5: pop
6: goto 14
9: astore_1
10: aload_1
11: invokevirtual #5; //Method java/lang/ClassNotFoundException.printStackTrace:()V
14: return
Exception table:
from to target type
0 6 9 Class java/lang/ClassNotFoundException
}
可见ClassNotFoundException异常可能会在0~6之间抛出,9开始处的代码处理此异常。
当产生异常的时候,jvm将会在整个异常表中搜索与之匹配的项,如果当前pc在异常表入口所指的范围内,并且所抛出的异常是此入口所指向的类或者其子类,则跳转到对应的处理代码继续执行。
方法可能会抛出哪些已检查异常
Class文件的attribute_info中保存有Exceptions属性,记录着每个方法throws的异常信息。具体的可以查看class类文件格式相关的文章。
athrow指令从栈顶弹出Throwable对象引用,抛出异常。
finally语句
在jvm规范中,finally语句是通过jsr/jsr_w与ret指令实现的。当执行jsr/jsr_w的时候将finally执行完成后的返回地址压入栈中,进入finally后会马上将此地址保存到一个局部变量中,执行完成后,ret从此局部变量中取出返回地址。???为什么会先把返回地址保存到局部变量中呢???因为,当从finally语句返回的时候需要将返回地址成栈中弹出,当finally语句非正常结束(break,continue,return, 抛异常)的时候就不用再考虑这个问题。
以下是jvm规范中Compiling finally的一段:
void tryFinally() {
try {
tryItOut();
} finally {
wrapItUp();
}
}
the compiled code is
Method void tryFinally()
0 aload_0 // Beginning of try block
1 invokevirtual #6 // Method Example.tryItOut()V
4 jsr 14 // Call finally block
7 return // End of try block
8 astore_1 // Beginning of handler for any throw
9 jsr 14 // Call finally block
12 aload_1 // Push thrown value
13 athrow // ...and rethrow the value to the invoker
14 astore_2 // Beginning of finally block
15 aload_0 // Push this
16 invokevirtual #5 // Method Example.wrapItUp()V
19 ret 2 // Return from finally block
Exception table:
From To Target Type
0 4 8 any
当tryItOut排除任何异常后都将会被异常表中的any项捕获,执行完finally后,会执行athrow指令将异常抛出。
从jdk的某一个版本开始就不会编译出编译出含jsr/jsr_w、ret的字节码了,因为有指令上的缺陷,导致jvm的检验和分析系统出现漏洞。(从rednaxelafx处得知)
再说finally的非正常退出
在finally中使用break、continue、return、抛出异常等认为是finally的非正常结束。非正常结束的时候,ret指令不会被执行,很可能会出现意想不到的结果。如:
public class Test {
public static boolean test(boolean b) {
while (b) {
try {
return true;
} finally {
/*
break; 始终返回false
continue; javac编译再java执行会出现死循环
在eclipse中甚至会出现报错:提示找到不main class
return false; 始终返回false
throw new RuntimeException(""); 抛出异常
*/
}
}
return false;
}
public static void main(String[] args) {
System.out.println(test(true));
}
}
建议:在写finally语句的时候,尽量避免非正常结束!
分享到:
相关推荐
JVM——总结思维导图
Java面试准备——异常处理 本文学习自GitHub上的JavaGuide项目,感谢大佬的资源,此处为自我学习与整理,原项目链接 JavaGuide Java异常类层次结构图 Java中所有的异常都有一个祖先java.lang.Throwable。Throwable...
异常处理的两大元素:抛出异常、捕获异常,非正常处理的两个方法。下面这篇文章主要给大家介绍了关于JVM如何处理异常的相关资料,文中通过示例代码介绍的非常详细,需要的朋友可以参考下
实战Java虚拟机——JVM故障诊断与性能优化.pdf 实战Java虚拟机——JVM故障诊断与性能优化.pdf
《实战Java虚拟机——JVM故障诊断与性能优化》内容简介:随着越来越多的第三方语言(Groovy、Scala、JRuby等)在Java虚拟机上运行,Java也俨然成为一个充满活力的生态圈。本书将通过200余示例详细介绍Java虚拟机中的...
看你简历写得熟悉JVM,那你说说类的加载过程吧? 我们可以自定义一个String类来使用吗? 什么是类加载器,类加载器有哪些? 多线程的情况下,类的加载为什么不会出现重复加载的情况? 什么是双亲委派机制?它有啥...
学习笔记——JVM性能调优之 jstat(csdn)————程序
JVM异常分析文件
java jvm-old gc耗时几十s,导致系统告警(csdn)————程序
JVM=类加载器classloader+执行引擎executionengine+运行时数据区域runtimedataarea首先Java源代码文件被Java编译器编译为字节码文件,然后JVM中的类加载器加载完毕之后,交由JVM执行引擎执行。在整个
本文来自于cnblogs,文章主要从基础概念说起,又讲解了体系结构,Java的异常处理机制,异常链等相关,详细内容请看下文。异常是程序中的一些错误,但并不是所有的错误都是异常,并且错误有时候是可以避免的。比如说,...
《实战Java虚拟机——JVM故障诊断与性能优化》将通过200余示例详细介绍Java虚拟机中的各种参数配置、故障排查、性能监控以及性能优化。, 《实战Java虚拟机——JVM故障诊断与性能优化》共11章。第1~3章介绍了Java...
3. JVM 是如何处理异常的? 4. throw 和 throws 的区别是什么? 5. final、finally、finalize 有什么区别? 6. NoClassDefFoundError 和 ClassNotFoundException 区别? 7. try-catch-finally 中哪个部分可以省略?
JVM对异常的处理方法是:打印异常跟踪栈信息,并中止程序运行,这 就是前面程序在遇到异常后自动结束的原因。 •throws声明抛出只能在方法签名中使用,throws可以声明抛出多个异常类,多个异常类之间以逗 号隔...
——–回过头来看 博客说明 文章所涉及的资料来自互联网整理和个人总结,意在于个人学习和经验汇总,如有什么地方侵权,请联系本人删除,谢谢! 简介 Java虚拟机(Java Virtual Machine 简称JVM)是运行所有Java程序...
JVM ——word文档总结下载地址-附件资源
当前,以Hadoop、Spark为...这些大数据处理框架采用分布式架构,使用Java、Scala等面向对象语言编写,在集群节点上以Java虚拟机(JVM)为运行时环境执行计算任务,因此依赖JVM的自动内存管理机制来分配和回收数据对象.