第十章 异常处理
10.1 异常概述
java中,异常可分为:Checked异常和Uncheecked异常。
Unchecked异常包括java.lang.RuntimeException、java.lang.Error及他们的子类。其他的异常都是Checked异常。
所有的异常都要继承自java.lang.Throwable。如果一个方法有可能导致Checked异常抛出,则该方法要么需要捕获该异常并妥善处理,要么必须把该异常列在自己的throw子句中,否则无法通过编译。Unchecked则没有这个限制。注意,这只是java语法规定的!
10.2 异常抛出
查看java.lang.Exception或RuntimeException源代码发现他们的构造函数都调用超类java.lang.Throwable的构造函数,而这个构造函数又调用了本地方法fillStackTrace()就java虚拟机栈信息。先分析到这里,接下来我们需要先解决处理异常。
10.3 异常处理表
异常处理表是Code属性的一部分,它记录了方法是否有能力处理某种异常。它包括三个信息:处理那部分代码抛出的异常,哪类异常以及处理代码在哪里。
对于:
void catchOne() {
try {
tryItOut();
} catch(TestExc e) {
//处理异常
}
}
当tryItOut()方法通过athrow指令抛出TestExc异常时,JVM首先会查找tryItOut()方法的异常处理表,看他是否可以处理该异常。如果能,则跳转到相应字节码开始处理异常。如果不能,JVM会进一步查看它的调用者,即catchOne()方法的异常处理表。假设catchOne()仍然不能,则会递归查找,直到找到或者达到java虚拟机栈的底部。
Code属性中异常处理表说明:
Code_attribute {
...
u2 exception_table_length;
{
u2 start_pc; //try{}语句块第一条指令
u2 end_pc; //try{}语句块下一条执行
u2 handler_pc;
u2 catch_type //如果是0,则表示可处理所有异常
} excption_table[exception_table_length];
...
}
10.4 实现athrow指令。
athrow指令的操作数是一个异常对象引用,从操作数栈中弹出。如果这个引用是null,抛异常。否则看是否可以找到并跳转到异常处理代码。找的过程:从当前帧开始,遍历java虚拟机栈,查找方法异常处理表。假设便利到了帧F,如果在F对应的方法中找不到异常处理项,则把F弹出继续遍历。如果找到了,在跳转到异常处理代码之前,要先把F的操作数栈清空,然后把异常处理引用推入栈顶。如果便利完java虚拟机栈还是找不到,抛异常。
10.5 java虚拟机栈信息
需要记录帧正在执行哪行代码,方法名,类名,文件名。
第十一章 结束
11.1 System类是如何被初始化的
System类初始化分为两个阶段。第一个阶段由类初始化方法完成,在这个方法中registerNatives()方法会注册其他本地方法。第二个阶段由VM完成,在这个阶段会调用System.initializeSystemClass()方法。在这个方法中,设置了Syetem.in、Syetem.out、Syetem.err。
11.2 初始化System类
先新建一个JVM结构体实例,再加载sun.misc.VM。
11.3 System.out.println()是如何工作的。
System.out常量是PrintStream类型,他内部包装了一个BufferedOutputStream实例。这个BufferedOutputStream内部又包装了一个FileOutputStream实例。调用System.out.printfln()经过层层包装,到达了FileoutputStream类的writeBytes()本地方法。
11.4 总结
四大块:类加载器、运行时数据区、方法调用、解释器及指令。
尚未完成:class文件验证、内存管理、垃圾回收、类加载器的委派模型、多线程、JIT等等....
-----------------------------------------------------------------------------------------------------------------------------------------------------
笔者语:结束了。幸亏我习惯在看书的时候做笔记,否则再看一遍书真的头疼。这次的总结用了三天的时间,我对jvm又有了更深的印象。最后再次感谢张秀宏老师!