【Java 虚拟机原理】Class 字节码二进制文件分析 七 ( 局部变量表分析 )

举报
韩曙亮 发表于 2022/01/14 00:24:26 2022/01/14
【摘要】 文章目录 前言一、编译生成带局部变量表的字节码文件二、局部变量表 前言 上一篇博客 【Java 虚拟机原理】Class 字节码二进制文件分析 二 ( 常量池位置 | 常量池结构 | tag...

前言

上一篇博客 【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;
    }
}

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

在 main 函数中 创建上述 Student 类对象 : 一定要写这个 main 函数 , 否则虚拟机编译优化时 , 发现 setName 中的局部变量没有使用 , 直接优化掉 , 不生成相关的 局部变量表 ;

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

  
 
  • 1
  • 2
  • 3
  • 4
  • 5

找到上述两个类编译后的字节码文件 : 根据上一篇博客 【Java 虚拟机原理】Class 字节码二进制文件分析 二 ( 常量池位置 | 常量池结构 | tag | info[] | 完整分析字节码文件中的常量池二进制数据 ) 分析 , 常量池是如下选中的区域 ;

在这里插入图片描述

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"

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96




二、局部变量表



在 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

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28

方法的最后有一个局部变量表 : 该局部变量表就是 " 线程栈 " 中维护的 " 栈帧 " 的 " 局部变量表 " ;

局部变量表 在 编译时 , 就已经在字节码文件中 生成好了 , 在 类加载器 将字节码文件加载到内存中时 , 直接将 字节码中的数据加载到

      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
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

局部变量表的第一行肯定是 局部变量 所在类 ;

局部变量表从 1 1 1 开始计数 , 并不是没有第 0 0 0 个元素 , 第 0 0 0 个元素是当前类 this , 这是所有的局部变量表固定的格式 ;


回顾 【Java 虚拟机原理】垃圾回收算法 ( Java 虚拟机内存分区 | 垃圾回收机制 | 引用计数器算法 | 引用计数循环引用弊端 ) 一、Java 虚拟机内存分区 章节内容 ;

整个 JVM 内存区域分为 方法区 , 堆区 , 线程栈 , 本地方法栈 , 程序计数器 ;

其中 线程栈 中维护 栈帧 , 每个栈帧 中维护 局部变量表 , 操作数栈 , 动态链接 , 方法出口 ; 这里的 局部变量表 就是本博客介绍的 字节码文件 的局部变量表 ;

在这里插入图片描述

文章来源: hanshuliang.blog.csdn.net,作者:韩曙亮,版权归原作者所有,如需转载,请联系作者。

原文链接:hanshuliang.blog.csdn.net/article/details/120107764

【版权声明】本文为华为云社区用户转载文章,如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。