天天看點

【Java 虛拟機原理】Class 位元組碼二進制檔案分析 七 ( 局部變量表分析 )

文章目錄

  • 前言
  • 一、編譯生成帶局部變量表的位元組碼檔案
  • 二、局部變量表

前言

上一篇部落格 【Java 虛拟機原理】Class 位元組碼二進制檔案分析 二 ( 常量池位置 | 常量池結構 | tag | info[] | 完整分析位元組碼檔案中的常量池二進制資料 ) ;

一、編譯生成帶局部變量表的位元組碼檔案

在 IntelliJ IDEA 中編寫如下兩個源碼 :

Java 類源碼 : 在 setName 方法下 , 聲明

3

3

3 個局部變量 ;

public class Student {
    private String name;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
        int i = 0;
        int j = 1;
        int k = 2;
    }
}
           

在 main 函數中 建立上述 Student 類對象 : 一定要寫這個 main 函數 , 否則虛拟機編譯優化時 , 發現 setName 中的局部變量沒有使用 , 直接優化掉 , 不生成相關的 局部變量表 ;

public class Main {
    public static void main(String[] args) {
        Student student = new Student();
    }
}
           

找到上述兩個類編譯後的位元組碼檔案 : 根據上一篇部落格 【Java 虛拟機原理】Class 位元組碼二進制檔案分析 二 ( 常量池位置 | 常量池結構 | tag | info[] | 完整分析位元組碼檔案中的常量池二進制資料 ) 分析 , 常量池是如下選中的區域 ;

【Java 虛拟機原理】Class 位元組碼二進制檔案分析 七 ( 局部變量表分析 )

Student.class 位元組碼檔案的附加資訊如下 :

Y:\002_WorkSpace\003_IDEA\Demo\out\production\Demo>javap -v Student.class
Classfile /Y:/002_WorkSpace/003_IDEA/Demo/out/production/Demo/Student.class
  Last modified 2021-9-5; size 561 bytes
  MD5 checksum 76a00ba8cb4c4c6aadc52f90e550d7e8
  Compiled from "Student.java"
public class Student
  minor version: 0
  major version: 52
  flags: ACC_PUBLIC, ACC_SUPER
Constant pool:
   #1 = Methodref          #4.#24         // java/lang/Object."<init>":()V
   #2 = Fieldref           #3.#25         // Student.name:Ljava/lang/String;
   #3 = Class              #26            // Student
   #4 = Class              #27            // java/lang/Object
   #5 = Utf8               name
   #6 = Utf8               Ljava/lang/String;
   #7 = Utf8               <init>
   #8 = Utf8               ()V
   #9 = Utf8               Code
  #10 = Utf8               LineNumberTable
  #11 = Utf8               LocalVariableTable
  #12 = Utf8               this
  #13 = Utf8               LStudent;
  #14 = Utf8               getName
  #15 = Utf8               ()Ljava/lang/String;
  #16 = Utf8               setName
  #17 = Utf8               (Ljava/lang/String;)V
  #18 = Utf8               i
  #19 = Utf8               I
  #20 = Utf8               j
  #21 = Utf8               k
  #22 = Utf8               SourceFile
  #23 = Utf8               Student.java
  #24 = NameAndType        #7:#8          // "<init>":()V
  #25 = NameAndType        #5:#6          // name:Ljava/lang/String;
  #26 = Utf8               Student
  #27 = Utf8               java/lang/Object
{
  public Student();
    descriptor: ()V
    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 1: 0
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0       5     0  this   LStudent;

  public java.lang.String getName();
    descriptor: ()Ljava/lang/String;
    flags: ACC_PUBLIC
    Code:
      stack=1, locals=1, args_size=1
         0: aload_0
         1: getfield      #2                  // Field name:Ljava/lang/String;
         4: areturn
      LineNumberTable:
        line 5: 0
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0       5     0  this   LStudent;

  public void setName(java.lang.String);
    descriptor: (Ljava/lang/String;)V
    flags: ACC_PUBLIC
    Code:
      stack=2, locals=5, args_size=2
         0: aload_0
         1: aload_1
         2: putfield      #2                  // Field name:Ljava/lang/String;
         5: iconst_0
         6: istore_2
         7: iconst_1
         8: istore_3
         9: iconst_2
        10: istore        4
        12: return
      LineNumberTable:
        line 9: 0
        line 10: 5
        line 11: 7
        line 12: 9
        line 13: 12
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0      13     0  this   LStudent;
            0      13     1  name   Ljava/lang/String;
            7       6     2     i   I
            9       4     3     j   I
           12       1     4     k   I
}
SourceFile: "Student.java"
           

二、局部變量表

在 Student 的 setName 方法中 , 定義了

3

3

3 個局部變量 , 将 setName 方法的對應位元組碼的附加資訊提取出來單獨分析 , 該方法對應的位元組碼資料中 , 肯定有局部變量表 ;

public void setName(java.lang.String);
    descriptor: (Ljava/lang/String;)V
    flags: ACC_PUBLIC
    Code:
      stack=2, locals=5, args_size=2
         0: aload_0
         1: aload_1
         2: putfield      #2                  // Field name:Ljava/lang/String;
         5: iconst_0
         6: istore_2
         7: iconst_1
         8: istore_3
         9: iconst_2
        10: istore        4
        12: return
      LineNumberTable:
        line 9: 0
        line 10: 5
        line 11: 7
        line 12: 9
        line 13: 12
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0      13     0  this   LStudent;
            0      13     1  name   Ljava/lang/String;
            7       6     2     i   I
            9       4     3     j   I
           12       1     4     k   I
           

方法的最後有一個局部變量表 : 該局部變量表就是 " 線程棧 " 中維護的 " 棧幀 " 的 " 局部變量表 " ;

局部變量表 在 編譯時 , 就已經在位元組碼檔案中 生成好了 , 在 類加載器 将位元組碼檔案加載到記憶體中時 , 直接将 位元組碼中的資料加載到

LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0      13     0  this   LStudent;
            0      13     1  name   Ljava/lang/String;
            7       6     2     i   I
            9       4     3     j   I
           12       1     4     k   I
           

局部變量表的第一行肯定是 局部變量 所在類 ;

局部變量表從

1

1

1 開始計數 , 并不是沒有第

0 個元素 , 第

0 個元素是目前類

this

, 這是所有的局部變量表固定的格式 ;

回顧 【Java 虛拟機原理】垃圾回收算法 ( Java 虛拟機記憶體分區 | 垃圾回收機制 | 引用計數器算法 | 引用計數循環引用弊端 ) 一、Java 虛拟機記憶體分區 章節内容 ;