JVM003_属性表

属性表

预备知识

  • javac -g Xxx.java 在生成class文件的时候生成所有调试信息
  • javap -v Xxx.class 输出附加信息

属性表结构

类型名称数量备注
u2attribute_name_index1属性名称索引,指向一个CONSTANT_Utf8_info型常量的索引
u4attribute_length1该属性表的长度
u1infoattribute_length属性值

Code属性表

在这里插入图片描述

Code属性表结构释义

  • attribute_name_index是一项指向CONSTANT_Utf8_info型常量的索引,对应的值固定为‘Code’,代表了该属性的属性名称。

  • attribute_length代表了属性值的长度。属性值的长度=属性表总长度-6个字节。

  • max_stack代表操作数栈深度的最大值。虚拟机运行时根据该值来分配栈帧中操作数栈的深度。

  • max_locals 代表了局部变量表所需的存储空间。其计算单位为‘变量槽’。变量槽是JVM为局部变量表分配内存所使用的最小单位。对于byte、char、float、int、short、boolean及returnAddress等长度不超过32位的数据类型,每个局部变量占用1个变量槽,double及long这两种64位的数据类型,占用两个变量槽。

    • 局部变量表中的变量槽会被复用,所以变量槽的个数不一定等于参数个数。当代码执行 超过一个变量的作用域时,其原型占用的变量槽将会被复用。
    • 操作数栈及局部变量表直接决定了该方法的栈帧所耗费的内存。
  • code_length代表Java源程序编译后生成的字节码指令个数,由于一个字节码占用1字节,所以也就是字节码的长度。

    • 理论值为2^32,实际最大值为65535。
  • code 用于存储编译生产的一些列字节码指令。

  • exception_info 该方法的显示异常处理表集合,非必须。

    • 显示异常处理表结构

      类型名称数量
      u2start_pc1
      u2end_pc1
      u2handler_pc1
      u2catch_type1

      上表表示当字节码从[start_pc,end_pc)行出现了类型为catch_type或其子类的异常,那么就转至handler_pc行进行处理。当catch_type为0时,代表任意异常都需要跳转到handler_pc行处理。

      -注意 : 此处的行指的是字节码相对于方法体开始的偏移量。

Code属性表实例

public class Test{private static final int size = 100;public void sout(){System.out.println(size);}public int toDouble(int prame){return 2*prame;}public int add(int p1,int p2){return p1+p2;}public static int toTriple(int prame){return 3*prame;}
}

将代码编译 javac -g Test.java,在反编译javap -v Test.class

Classfile /D:/notes/JVM/code/Test.classLast modified 2021-3-29; size 746 bytesMD5 checksum a1a23cf998350d444d9438782f3af659Compiled from "Test.java"
public class Testminor version: 0major version: 52flags: ACC_PUBLIC, ACC_SUPER
Constant pool:#1 = Methodref          #5.#28         // java/lang/Object."<init>":()V#2 = Fieldref           #29.#30        // java/lang/System.out:Ljava/io/PrintStream;#3 = Class              #31            // Test#4 = Methodref          #32.#33        // java/io/PrintStream.println:(I)V#5 = Class              #34            // java/lang/Object#6 = Utf8               size#7 = Utf8               I#8 = Utf8               ConstantValue#9 = Integer            100#10 = Utf8               <init>#11 = Utf8               ()V#12 = Utf8               Code#13 = Utf8               LineNumberTable#14 = Utf8               LocalVariableTable#15 = Utf8               this#16 = Utf8               LTest;#17 = Utf8               sout#18 = Utf8               toDouble#19 = Utf8               (I)I#20 = Utf8               prame#21 = Utf8               add#22 = Utf8               (II)I#23 = Utf8               p1#24 = Utf8               p2#25 = Utf8               toTriple#26 = Utf8               SourceFile#27 = Utf8               Test.java#28 = NameAndType        #10:#11        // "<init>":()V#29 = Class              #35            // java/lang/System#30 = NameAndType        #36:#37        // out:Ljava/io/PrintStream;#31 = Utf8               Test#32 = Class              #38            // java/io/PrintStream#33 = NameAndType        #39:#40        // println:(I)V#34 = Utf8               java/lang/Object#35 = Utf8               java/lang/System#36 = Utf8               out#37 = Utf8               Ljava/io/PrintStream;#38 = Utf8               java/io/PrintStream#39 = Utf8               println#40 = Utf8               (I)V
{public Test();descriptor: ()Vflags: ACC_PUBLICCode:stack=1, locals=1, args_size=10: aload_01: invokespecial #1                  // Method java/lang/Object."<init>":()V4: returnLineNumberTable:line 1: 0LocalVariableTable:Start  Length  Slot  Name   Signature0       5     0  this   LTest;    // 疑问:为什么这里的Length为5?public void sout();descriptor: ()Vflags: ACC_PUBLICCode:stack=2, locals=1, args_size=10: getstatic     #2                  // Field java/lang/System.out:Ljava/io/PrintStream;3: bipush        1005: invokevirtual #4                  // Method java/io/PrintStream.println:(I)V8: returnLineNumberTable:line 5: 0line 6: 8LocalVariableTable:Start  Length  Slot  Name   Signature0       9     0  this   LTest;public int toDouble(int);descriptor: (I)Iflags: ACC_PUBLICCode:stack=2, locals=2, args_size=20: iconst_21: iload_12: imul3: ireturnLineNumberTable:line 9: 0LocalVariableTable:Start  Length  Slot  Name   Signature0       4     0  this   LTest;0       4     1 prame   Ipublic int add(int, int);descriptor: (II)Iflags: ACC_PUBLICCode:stack=2, locals=3, args_size=30: iload_11: iload_22: iadd3: ireturnLineNumberTable:line 13: 0LocalVariableTable:Start  Length  Slot  Name   Signature0       4     0  this   LTest;0       4     1    p1   I0       4     2    p2   Ipublic static int toTriple(int);descriptor: (I)Iflags: ACC_PUBLIC, ACC_STATICCode:stack=2, locals=1, args_size=10: iconst_31: iload_02: imul3: ireturnLineNumberTable:line 17: 0LocalVariableTable:Start  Length  Slot  Name   Signature0       4     0 prame   I
}

现在对toDouble方法进行分析

在这里插入图片描述

Code属性下

  • stack=2表示操作数栈的最大深度为2
  • locals=2表示本地变量表的存储空间为2个变量槽
  • args_size=2表示方法的传参有2个
    • 这里有个问题,明明方法签名为toDouble(int prame),只有一个参数,为什么这里显示有两个参数呢?因为在编译的时候,会自动的传入一个参数this。并放到局部变量表的0号槽中。
  • LocalVariableTable 表示各变量在局部变量表中的存储情况。
Code:stack=2, locals=2, args_size=20: iconst_2 # 将int型数值2推送到操作数栈顶1: iload_1  # 将第二个int型本地变量推动至栈顶,即将局部变量表中solt索引为1的变量推送至操作数栈栈顶2: imul	 # 将栈顶两个int类型数值相乘并将结果压入栈顶3: ireturn  # 从方法中返回int类型的数据,即将操作数栈栈顶元素弹出

Exceptions属性

Exceptions属性是在方法表中与Code属性平级的一项属性,与Code属性中的异常表不是同一东西,列举出方法中可能抛出的受查异常(Checked Excepitons) , 也就是方法描述时在throws关键字后面列举的异常。

Exceptions属性结构

类型名称数量备注
u2attribute_name_index1属性名索引
u4attribute_length1属性长度
u2number_of_exceptions1抛出的受查异常种数
u2exception_index_tablenubmer_of_exceptions指向常量池中CONSTANT_class_info型常量的索引

LineNumberTable属性

用来描述Java源码与字节码行号之间的对应关系。这里的字节码行号指的是字节码距方法体开始的偏移量。是一个非必须属性。默认生成。可使用-g: none-g:lines来选择或者取消。

若不生成改属性,那么在抛出异常的时候,堆栈中将不会显示出错的行号,在调试时无法按照源码行来设置断点。

LineNumberTable属性结构

类型名称数量备注
u2attribute_name_index1属性名索引
u4attribute_length1属性长度
u2line_number_table_length1属性个数
line_number_infoline_number_tableline_number_table_lengthline_number_info集合

line_number_info

类型名称备注
u2start_pc字节码行号
u2line_numberJava源码行号

LocalVariableTable

用来描述栈帧中局部变量表的变量与Java源码中定义的变量之间的关系,是非必须的。-g:none,-g: vars来取消或选择。默认会生成到class文件中,若取消该属性,那么当他人引用时,所有的参数名称都会消失。

LocalVariableTable属性结构

类型名称数量备注
u2attribute_name_index1属性名索引
u4attribute_length1属性长度
u2local_variable_table_length1本地变量表长度
local_variable_infolocal_variable_tablelocal_variable_table_length本地变量表

local_variable_info结构

类型名称数量备注
u2start_pc1该局部变量的声明周期的开始字节码偏移量
u2length1该局部变量的作用范围
u2name_index1是指向CONSTANT_Utf8_info型常量的索引,代表局部变量的名称
u2descriptor_index1是指向CONSTANT_Utf8_info型常量的索引,代表局部变量的描述符
u2index1在局部变量表中的变量槽位置

在JDK引入泛型后增加了**LocalVariableTypeTable **属性,仅仅是将descriptor_index替换为字段的特征签名(Signature) 。

SourceFile及SourceDebugExtension属性

SourceFile属性用于记录生成这个Class文件的源码文件名称。 可选;-g:none,-g: source来关闭或开启。若不生成,在抛出异常的时候,堆栈中不会显示出错代码所属的文件名。

SouceFile属性结构

类型名称数量备注
u2attribute_name_index1属性名索引
u4attribute_length1属性长度
u2sourcefile_index1指向常量池中CONSTANT_Utf8_info型常量的索引, 常量值是源码文件的文件名

JDK 5时, 新增了SourceDebugExtension属性用于存储额外的代码调试信息。

类型名称数量备注
u2attribute_name_index1属性名索引
u4attribute_length1属性长度
u1debug_extension[attribute_length]1额外的调试信息

ConstantValue属性

该属性的作用是通知虚拟机自动为静态变量赋值。只有被static修饰的变量才能使用这项属性。

非静态变量实例构造器()方法中赋值
静态变量类构造器()方法中赋值
静态变量使用ConstantValue属性

Oracle公司的选择是,常量(static final共同修饰的变量)且其类型为基础类型或String,使用ConstantValue属性来进行初始化,非基础类型及字符串,或仅被static修饰那么在()中进行初始化。

ConstantValue属性结构

类型名称数量备注
u2attribute_name_index1属性名索引
u4attribute_length1属性长度
u2constantvalue_index1常量池中一个字面量的引用

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/558756.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Lombok ——自动化方法生成器

引言 此文为简单的Lombok 演示。 Lombok是一个可以通过简单的注解形式来帮助我们简化消除一些必须有但显得很臃肿的Java代码的工具&#xff0c;通过使用对应的注解&#xff0c;可以在编译源码的时候生成对应的方法。简而言之&#xff0c;一句话就是&#xff1a;通过简单的注解…

LeetCode(#26)————删除排序数组中的重复项

题目 给定一个排序数组&#xff0c;你需要在原地删除重复出现的元素&#xff0c;使得每个元素只出现一次&#xff0c;返回移除后数组的新长度。 不要使用额外的数组空间&#xff0c;你必须在原地修改输入数组并在使用 O(1) 额外空间的条件下完成。 示例 1: 给定数组 nums […

JVM006_类加载的过程

类加载 类加载时机 类加载的过程 新术语 类加载器 简单的理解为将类转换为二进制流的类或接口。 数组的元素类型 数组去掉所有维度的类型。 数组的组件类型 数组去掉一个维度的类型。 基本块 按照控制流拆分的代码块。 1. 加载 加载是类加载过程的一个阶段。加载阶段主…

服务端开发——云服务器的端口转发设置(SSH隧道)

引言 本篇博客介绍端口转发的知识&#xff0c;并详细阐述操作和设置步骤。这是因为在实际工作中&#xff0c;会有很多企业从安全的角度考虑&#xff0c;为线上或重要的服务器设置一个跳板机&#xff08;堡垒机&#xff09;&#xff0c;避免远程开发人员直接操作&#xff0c;是…

Shiro————核心设计思想

引言 以此篇博客为引&#xff0c;开启一个新的专栏分类——Shiro。 之前在工作中有比较快速的学习过Shiro安全框架&#xff0c;但经过一年的荒废&#xff0c;已经不是很熟悉了&#xff0c;通过这个系列&#xff0c;深入研究和学习Shiro的一些知识&#xff0c;填补安全管理方面…

Web应用安全————账号冻结与 Session 实时失效

引言 开篇时说些题外话&#xff0c;最近刚刚被公司CY&#xff0c;不过很快找到了下家&#xff0c;也同时拿到了三家公司的Offer。一周面试下来&#xff0c;总体感觉面试题少了&#xff0c;不过多了上机程序题。新公司是做外包&#xff0c;不过相比于上一家公司&#xff0c;也算…

Web应用安全————Shiro 解决会话固定漏洞

引言 承接上一篇《Web应用安全————账号冻结与 Session 实时失效》关于 session 的学习&#xff0c;本篇博客聚焦如何通过 shiro 解决会话固定导致的漏洞问题。 首先&#xff0c;没怎么接触过应用安全方面的小伙伴可能会发起疑问 - 什么是会话固定&#xff1f; 简单来说&…

Web应用安全————多点登录互斥

引言 在实际生活中&#xff0c;很多网站都做了多点登录互斥的操作&#xff0c;简单来说就是同一个账号&#xff0c;只能在一台电脑上登录&#xff0c;如果有人在其他地方登录&#xff0c;那么原来登录的地方就会自动下线&#xff0c;再进行操作就会弹出登录界面。 实现思路 …

Linux进阶之路————磁盘查询

引言 承接《Linux进阶之路————Linux磁盘分区与挂载》&#xff0c;本文介绍实际生产中对于磁盘的监控和查询。 一、查询磁盘整体使用情况 基本语法&#xff1a; df -h 该命令会显示包括我们手动挂载的磁盘&#xff0c;如果使用 umount 卸载磁盘&#xff0c;那么将不会显示…

Linux进阶之路————CentOS网络配置

引言 Linux在装机后&#xff0c;如果没有特殊配置&#xff0c;会使用动态获取 IP 地址的策略。本文描述了&#xff0c;虚拟机使用网络的拓扑图&#xff0c;以及如何通过配置&#xff0c;将 IP 地址固定下来&#xff0c;不会因为重启而失效。同时可以访问外网地址。 一、NAT模…

Linux进阶之路————进程与服务管理

引言 在Linux 中&#xff0c;每个执行的程序&#xff08;代码&#xff09;都成为一个进程&#xff0c;Linux 为每一个进程分配了一个唯一的 id 号 - PID。 每个进程都会对应一个父进程&#xff0c;而这个父进程可以复制多个子进程&#xff0c;例如 www 服务器。 每个进程都可…

Linux进阶之路———— RPM 与 YUM 包管理

引言 rpm 是一种用于互联网下载的打包及安装工具&#xff0c;它包含在某些 Linux 发行版中&#xff0c;生成具有 .rpm 扩展名的文件。rpm 是 redhat package manager&#xff08;RedHat 软件包管理器&#xff09;的缩写&#xff0c;类似 Windows 下的 setup.exe 文件。这一文件…

Linux进阶之路———Shell 编程入门

引言 通过 Shell 编程的学习&#xff0c;铺平架构师道路上的一块大砖。 Shell 在Linux 系统中的定位如下所示&#xff1a; 一、第一个 Shell 脚本 我们通过一个简单的 Shell 脚本来感受一下。 在 Shell 中不需要加 “;” 结尾&#xff0c;通过 vim 可以进行 shell 的编程工…

Linux 实操———CentOS 6 安装配置 Oracle JDK 1.8

引言 本篇博客也属于Linux进阶系列&#xff0c;主要讲解如何在CentOS 6 下安装并配置 JDK 8。由于通过 yum 搜索的结果都是 openjdk&#xff0c;而目前企业中还是以 Oracle jdk 为主&#xff0c;因此&#xff0c;操作步骤这样的。 在Oracle 官网把 jdk 1.8 下载下来&#xff…

Linux 实操———CentOS 6 安装配置 Tomcat

引言 Linux下安装Tomcat。 一、下载、传输与解压 同《Linux 实操———CentOS 6 安装配置 Oracle JDK 1.8》一样&#xff0c;前期都是先在远程机上下载压缩包&#xff0c;然后通过远程终端&#xff0c;将压缩包放在 Linux 的 opt 目录下&#xff0c;然后解压。 下载地址是T…

Spring Boot 实用开发技巧————Eclipse 远程调试

引言 在之前的开发当中&#xff0c;都会进行本地项目启动&#xff0c;然后向本地服务发起请求来进行 Debug 调试代码&#xff0c;这也是开发人员最常见的调试操作。但是当项目逐渐成型&#xff0c;慢慢的将各个模块部署到服务器后&#xff0c;调试的手段可能就仅仅剩下查看执行…

Linux 实操———— Shell 远程执行命令

引言 目前&#xff0c;开发人员的部署方式是&#xff0c;将项目打包(Maven 打包) 然后将 生成的 jar 包等文件&#xff0c;通过Xshell 等终端工具手动传输到远程服务器上&#xff0c;然后再通过在终端执行远程服务器上的 shell 脚本来启动服务。 本篇博客聚焦这样一种解决方案…

Spring Boot 设置 ASCII banner 艺术字

引言 无意中看到Spring boot 项目的 resources 目录下有一个 banner.txt &#xff0c;打开一看&#xff0c;居然是ASCII 字符画。于是兴起&#xff0c;简单研究了一下。 Spring boot 可以加载 resources 目录下的 banner.txt 文件&#xff0c;将字符画在启动之初输出到日志或…

MySQL 基础 ———— 分组查询

引言 承接上一篇《MySQL 基础 ————高频函数总结》&#xff0c;本篇单独针对分组查询进行简单的总结和归纳&#xff0c;并为后续更为复杂的DQL 语句做好铺垫。 查询语句&#xff1a; SELECT AVG(salary) FROM teacher; 实际上是以全表的 salary 字段来求平均值。但是在实…

MySQL 基础 ———— 连接查询

引言 本篇文章承接《数据库与SQL语句》专栏&#xff0c;进入DQL的重要环节&#xff0c;可以说&#xff0c;这一部分的内容应该占据SQL语言的大部分使用场景。 本篇的连接查询知识&#xff0c;和后面的一些重要的查询知识总结&#xff0c;共同构成了在工作中80%的MySQL应用场景…