【JVM学习笔记】异常表的重要作用以及locals属性的含义

有如下代码

public class Test {
    public void work() {
        try {
            InputStream is = new FileInputStream("test.txt");
            ServerSocket serverSocket = new ServerSocket(9999);
            serverSocket.accept();
        } catch (FileNotFoundException e) {

        } catch (IOException e) {
            
        } catch (Exception e) {

        } finally {
            System.out.println("finally block");
        }
    }
}

javap -verbose -p Test 结果如下

D:\workspace-learn\common-learn\learn-classloader\target\classes\com\learn\jvm>javap -verbose -p Test
警告: 二进制文件Test包含com.learn.jvm.Test
Classfile /D:/workspace-learn/common-learn/learn-classloader/target/classes/com/learn/jvm/Test.class
  Last modified 2019-9-5; size 1075 bytes
  MD5 checksum 744e2b9632f4d7f2d38d6b77b4225cc2
  Compiled from "Test.java"
public class com.learn.jvm.Test
  SourceFile: "Test.java"
  minor version: 0
  major version: 51
  flags: ACC_PUBLIC, ACC_SUPER
Constant pool:
   #1 = Methodref          #15.#35        //  java/lang/Object."<init>":()V
   #2 = Class              #36            //  java/io/FileInputStream
   #3 = String             #37            //  test.txt
   #4 = Methodref          #2.#38         //  java/io/FileInputStream."<init>":(Ljava/lang/String;)V
   #5 = Class              #39            //  java/net/ServerSocket
   #6 = Methodref          #5.#40         //  java/net/ServerSocket."<init>":(I)V
   #7 = Methodref          #5.#41         //  java/net/ServerSocket.accept:()Ljava/net/Socket;
   #8 = Fieldref           #42.#43        //  java/lang/System.out:Ljava/io/PrintStream;
   #9 = String             #44            //  finally block
  #10 = Methodref          #45.#46        //  java/io/PrintStream.println:(Ljava/lang/String;)V
  #11 = Class              #47            //  java/io/FileNotFoundException
  #12 = Class              #48            //  java/io/IOException
  #13 = Class              #49            //  java/lang/Exception
  #14 = Class              #50            //  com/learn/jvm/Test
  #15 = Class              #51            //  java/lang/Object
  #16 = Utf8               <init>
  #17 = Utf8               ()V
  #18 = Utf8               Code
  #19 = Utf8               LineNumberTable
  #20 = Utf8               LocalVariableTable
  #21 = Utf8               this
  #22 = Utf8               Lcom/learn/jvm/Test;
  #23 = Utf8               work
  #24 = Utf8               is
  #25 = Utf8               Ljava/io/InputStream;
  #26 = Utf8               serverSocket
  #27 = Utf8               Ljava/net/ServerSocket;
  #28 = Utf8               StackMapTable
  #29 = Class              #47            //  java/io/FileNotFoundException
  #30 = Class              #48            //  java/io/IOException
  #31 = Class              #49            //  java/lang/Exception
  #32 = Class              #52            //  java/lang/Throwable
  #33 = Utf8               SourceFile
  #34 = Utf8               Test.java
  #35 = NameAndType        #16:#17        //  "<init>":()V
  #36 = Utf8               java/io/FileInputStream
  #37 = Utf8               test.txt
  #38 = NameAndType        #16:#53        //  "<init>":(Ljava/lang/String;)V
  #39 = Utf8               java/net/ServerSocket
  #40 = NameAndType        #16:#54        //  "<init>":(I)V
  #41 = NameAndType        #55:#56        //  accept:()Ljava/net/Socket;
  #42 = Class              #57            //  java/lang/System
  #43 = NameAndType        #58:#59        //  out:Ljava/io/PrintStream;
  #44 = Utf8               finally block
  #45 = Class              #60            //  java/io/PrintStream
  #46 = NameAndType        #61:#53        //  println:(Ljava/lang/String;)V
  #47 = Utf8               java/io/FileNotFoundException
  #48 = Utf8               java/io/IOException
  #49 = Utf8               java/lang/Exception
  #50 = Utf8               com/learn/jvm/Test
  #51 = Utf8               java/lang/Object
  #52 = Utf8               java/lang/Throwable
  #53 = Utf8               (Ljava/lang/String;)V
  #54 = Utf8               (I)V
  #55 = Utf8               accept
  #56 = Utf8               ()Ljava/net/Socket;
  #57 = Utf8               java/lang/System
  #58 = Utf8               out
  #59 = Utf8               Ljava/io/PrintStream;
  #60 = Utf8               java/io/PrintStream
  #61 = Utf8               println
{
  public com.learn.jvm.Test();
    flags: ACC_PUBLIC
    Code:
      stack=1, locals=1, args_size=1
         0: aload_0
         1: invokespecial #1                  // Method java/lang/Object."<init>":()V
         4: return
      LineNumberTable:
        line 14: 0
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
               0       5     0  this   Lcom/learn/jvm/Test;

  public void work();
    flags: ACC_PUBLIC
    Code:
      stack=3, locals=4, args_size=1
         0: new           #2                  // class java/io/FileInputStream
         3: dup
         4: ldc           #3                  // String test.txt
         6: invokespecial #4                  // Method java/io/FileInputStream."<init>":(Ljava/lang/String;)V
         9: astore_1
        10: new           #5                  // class java/net/ServerSocket
        13: dup
        14: sipush        9999
        17: invokespecial #6                  // Method java/net/ServerSocket."<init>":(I)V
        20: astore_2
        21: aload_2
        22: invokevirtual #7                  // Method java/net/ServerSocket.accept:()Ljava/net/Socket;
        25: pop
        26: getstatic     #8                  // Field java/lang/System.out:Ljava/io/PrintStream;
        29: ldc           #9                  // String finally block
        31: invokevirtual #10                 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
        34: goto          84
        37: astore_1
        38: getstatic     #8                  // Field java/lang/System.out:Ljava/io/PrintStream;
        41: ldc           #9                  // String finally block
        43: invokevirtual #10                 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
        46: goto          84
        49: astore_1
        50: getstatic     #8                  // Field java/lang/System.out:Ljava/io/PrintStream;
        53: ldc           #9                  // String finally block
        55: invokevirtual #10                 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
        58: goto          84
        61: astore_1
        62: getstatic     #8                  // Field java/lang/System.out:Ljava/io/PrintStream;
        65: ldc           #9                  // String finally block
        67: invokevirtual #10                 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
        70: goto          84
        73: astore_3
        74: getstatic     #8                  // Field java/lang/System.out:Ljava/io/PrintStream;
        77: ldc           #9                  // String finally block
        79: invokevirtual #10                 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
        82: aload_3
        83: athrow
        84: return
      Exception table:
         from    to  target type
             0    26    37   Class java/io/FileNotFoundException
             0    26    49   Class java/io/IOException
             0    26    61   Class java/lang/Exception
             0    26    73   any
            37    38    73   any
            49    50    73   any
            61    62    73   any
            73    74    73   any
      LineNumberTable:
        line 17: 0
        line 18: 10
        line 19: 21
        line 27: 26
        line 28: 34
        line 20: 37
        line 27: 38
        line 28: 46
        line 22: 49
        line 27: 50
        line 28: 58
        line 24: 61
        line 27: 62
        line 28: 70
        line 27: 73
        line 29: 84
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
              10      16     1    is   Ljava/io/InputStream;
              21       5     2 serverSocket   Ljava/net/ServerSocket;
               0      85     0  this   Lcom/learn/jvm/Test;
      StackMapTable: number_of_entries = 5
           frame_type = 101 /* same_locals_1_stack_item */
          stack = [ class java/io/FileNotFoundException ]
           frame_type = 75 /* same_locals_1_stack_item */
          stack = [ class java/io/IOException ]
           frame_type = 75 /* same_locals_1_stack_item */
          stack = [ class java/lang/Exception ]
           frame_type = 75 /* same_locals_1_stack_item */
          stack = [ class java/lang/Throwable ]
           frame_type = 10 /* same */

}

在上图中看到work方法的 stack=3, locals=4, args_size=1,其中size = 1表示参数个数为一个,即this,locals=4表示有4个局部变量,分别为 this,is,serverSocket,和 e,虽然有三个catch块,但是程序运行时只可能进入其中某一个,所以只有一个e

对异常表的解读

 异常表的第一行为例,表示在[0,25]行这个范围内如果发生FileNotFoundException,将会跳转到字节码第37行,如下图

 astore_1表示把一个引用赋值给局部变量e


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

  1. 统一采用异常表的方式来对异常进行处理
  2. 在jdk1.4.2之前的版本中,并不是使用异常表的方式来对异常进行处理的,而是采用特定的指令方式
  3. 当异常处理存在finally块时,现代化的jvm采取的处理方式是将finally语句块的字节码拼接到每一个catch块后面,换句话说,程序中存在多少个catch块,就会在每个catch块后面重复多少个finally语句块的字节码

最后,如果方法后面throws了异常,则字节码里方法会多出一个属性,是这样的:

 很简单,知道即可

猜你喜欢

转载自www.cnblogs.com/heben/p/11470675.html