zoukankan      html  css  js  c++  java
  • 通过字节码分析Java异常处理机制

    在上一次【https://www.cnblogs.com/webor2006/p/9691523.html】初步对异常表相关的概念进行了了解,先来回顾一下:

    其源代码也贴一下:

    下面来看一下jclasslib关于这个test()的信息:

    咱们重点来看一下Code信息,如下:

    其实也就是对应于javap -verbose看到的字节码信息,咱们一行行的跟源代码进行比对一下:

    点击看一下new的助字符的官方解释:

    实际对应源码就是:

    查看一下官网的解释:

    查看一下解释:

    回到咱们这句话其意思就是将常量“test.txt”推到常量池中使得能构造出FileInputStream对象。

    这个我们之前了解过,这里再看一下官网的解释:

    回到咱们这句话意思就是调用了父类的构造方法,因为创建子类其父类肯定得要先被创建才行。

    也就是将"is"存到局部变量当中,所以前面的这些助记符就对应这样一个句源码,如下:

    对应于

    类似的下面这一行源代码其实对应的助字符差不多,如下:

    下面也来瞧一下:

     new一个对象:

    跟之前一样,将最顶层操作数栈的值进行复制,往下:

    其中sipush官网解释如下:

    这里有一个细节需要注意:源代码中的999其实是一个int类型的,如下:

    但是在字节码中999其实是属于short类型范围之内,所以是当一个short类型处理了。

    调用ServerSocket的构造方法及父类的,不多说比较容易理解。

    看一下它官网的解释:

    也就是将引用赋给了serverSocket变量。

     

    官网的解释:

    其实对于方法的调用方式都是基于操作栈的,所以有大量的入栈和出栈的一些操作在里面的。

    发现这对应于代码:

    由于catch块中没有写代码,所以直接就到了finally了。

    也就是finally这个关键字嘛。

    调用打印实例方法。

    接下来发现有大量的goto助记符:

    也就是对于异常在字节码的表现形式是通过goto来将整个执行进行中断的,为了能理解这里面的goto,此时需要先分析一下异常表信息,如下:

    其中可以整体看到“Catch Type”这行,刚好跟咱们捕获的异常能对应上,如下:

    其中还有最后一个:

    其中理论依据为:

    下面具体来看一下:

    发现Start PC和End PC都是从0到26,先来回顾一下这两个的含义:

     也就是表示:

    其实对应于源代码就是try的部分,如下:

    这段代码抛出任何异常都会有相应的异常表项来处理,咱们一一来看一下:

    也就是说如果代码发现了FileNotFoundException异常时,则会由37这个位置的Handler PC来处理异常,那37对应于哪呢?

    而astore_1表示:

    那如何理解呢?来看下源代码:

    很明显当生成异常时会将异常对象赋值给这个ex,所以就会有这样的一个引用赋值操作,由于这个catch块中没有写任何代码,所以就立马就执行到了finally块了,也就是对应于这段助记符:

    最后又有一个goto了,如下:

    第一个异常的整个字节码流程分析完之后,其它两个就基本类似了,咱们来过一遍:

    当发生异常则会跳到49的Handler PC,如下:

    接着再看第三个异常:

    然后会跳到61,看一下,一样的套路:

    好了对于咱们自己捕获的异常的内部处理机制已经非常之清楚了,剩最后一种异常情况下,如下:

    从程序角度照理应该是Exception已经包含所有可以捕获的异常了,但是从字节码角度并不这样认为,所以这也是为啥会有这么一个异常的情况出现,表示处理上面咱们手动捕获的之外不可能处理的异常,这是编译器自动为我们生成出来的,咱们来看一下73是啥:

    只是其中发现了一个athrow,这是个什么东东:

    至此,咱们就彻底把异常机制相关的东东完完整整的分析完了,下面来总结一下:

    Java字节码对于异常的处理方式:

    1、统一采用异常表的方式来对异常进行处理。

    2、在之前的JDK 1.4.2之前的版本中并不是使用异常表的方式来对异常进行处理的,而是采用特定的指令方式。【了解既可】

    3、当异常处理存在finally语句块时,现代化的JVM采取的处理方式是将finally语句块的字节码批接到每一个catch块后面,换句话说,程序中有多少个catch块,就会在每一个catch块后面重复多少个finally语句块的的字节码。从字节码就可以得知:

    关于异常表就了解到这,接下来了解另外一个信息,如下:

    根据之前的了解,我们也知道这个属性主要是描述字节码的位置对应源代码的行号,便于debug,如下:

    下面来一一细看一下:

    字节码0处对应源代码13行,瞅一下:

    其中的Start PC是指代码字节码的起始位置,刚好是对应的。

    继续:

    字节码10对应源代码14,看一下:

    完全能对应上,继续再挑一个看,由于规则是一样的,就没必要完全一个个对了,知道个大概作用就成:

    字节码49对应源代码18:

    所以通过这个就可以将字节码跟源代码对应起来。

    最后再来看一下它:

    发现jclasslib中只有3个,而之前在javap -verbose中看到的是有4个,回忆下:

    因为目前jcalsslib打开的是一个静态的class,并不知道是否抛出异常,所以静态的情况下就只能看到3个局部变量,javap -verbose上看到的是最大可以有4个局部变量,也就是一旦运行抛异常了那最终就有4个局部变量啦,没毛病的!

  • 相关阅读:

    python 爬取可用
    安装完出现Deprecated: Function ereg_replace() is deprecated in
    mysql数据库还原出错ERROR:Unknown command ‘\’解决手记
    mysql 常用语句
    This version of MySQL doesn't yet support 'LIMIT & IN/ALL/ANY/SOME subquery 解决方法
    js 中 json对象 与 json字符串 间相互转换
    神器 Sublime Text 3 的一些常用快捷键
    神器 Sublime Text 3 的一些常用插件
    apache php gzip压缩输出的实现方法
  • 原文地址:https://www.cnblogs.com/webor2006/p/9706466.html
Copyright © 2011-2022 走看看