《深入理解Java虚拟机》读书笔记五
第六章 类文件结构
1、无关性的基石
- 各种不同平台的虚拟机与所有平台都统一使用程序存储格式——字节码是构成平台无关的基石。
- 实现语言无关性的基础仍然是虚拟机和字节码存储格式,Java虚拟机不和包括Java在内的任何语言绑定只能与class文件这种特定的二进制文件格式所关联。
- class文件包含了Java虚拟机指令集和符号表以及若干其他辅助信息。
2、class文件结构
概述:
- class文件是一组以八位字节为基础的二进制流,各个数据项目严格按照顺序紧凑的排列在class文件中。
- class文件格式采用一种类似于C语言结构的伪数据结构来存储数据,这种伪数据结构包含两种数据类型无符号和表。
- 无符号数属于基本数据类型,从u1、u2、u4、u8来分别表示一个字节、两个字节、四个字节、八个字节的无符号数。无符号数可以用来描述数字、索引、引用7数量值或者按照utf-8编码构成字符串值。
- 表是由多个无符号或者其他表作为数据项构成的复合数据类型。所有的表都习惯性地以“_info”结尾。表示描述有层次关系的复合结构的数据,整个class文件本质就是一张表。
魔数:
- 每个class文件的头四位为魔数,作用是确定这个文件是否是一个能被虚拟机引用接受的class文件,class文件的魔数值是0xCAFEBABE。
class文件的版本:
- 紧接着魔数的四个字节存储的是class文件的版本号,第5和第6个字节是次版本号,第7和第8个是主版本号。
常量池:
- 紧接着主版本号的是常量池入口,常量池可以理解为class文件中的资源仓库,它是class文件结构中与其他项目关联的最多的数据类型,也是占有class文件空间最大的数据项目之一,同时它是class文件第一个出现的表类型数据。
- 由于常量池的常量数值不固定,所以在常量池的入口需要放置一项u2类型的数据代表常量池容量计数值,计数是从一开始的。
- 常量池主要存放两大常量,字面量和符号引用,字面量比较接近于Java语言层面的常量概念,如文字字符串,声明为final的常量池等。
- 符号引用包括类和接口的全限定名,字段的名称和描述符,方法的名称和描述符。
- 常量池中每一项常量都是一个表,根据标志位来确定项目类型。
package com.ecut.clazz;public class TestClass {private int m;public int inc() {return m + 1;} }
字节码文件对应的16进制如下图:
常量容量计数值为22则代表有21个常量,第一个常量的标志位是0x0A,根据下表可知对应的项目类型是CONSTANT_Methodref_info,此类型代表类中方法的符号引用,这个项目类型对应的结构有两个index,第一个index为0x0004为即十进制4,第二个index为0x0012即十进制18。第二个常量是以此类推,这个项目类型为CONSTANT_Fieldref_info,第一个index为0x0003即十进制3,第二个index为0x0013即十进制19。
- 剩下的常量可以借助class文件字节码的工具javap来输出TestClass.class文件字节码内容。采用javap -verbose TestClass.class命令。
访问标志:
- 在常量池结束之后,紧接着的两个字节代表访问标志,这个标志用于标识一些类或者接口层次的访问信息,包括是类还是接口,是否为public类型,是否为abstract。具体的标志位以及标志的含义如下表:
- access_flag中一共有16个标志位可以使用,当前只定义了其中8个,没有使用到的标志位要求一律为0。
- TestClass被public修饰并且使用了jdk1.2之后的编译器进行了编译,因此它的access_flag标志值应该为100001=0x21。
类索引、父类索引、接口索引:
- 类索引用于确定表达这个类的全限定名,父类索引用于确定这个类的父类的全限定名,接口索引集合就用于描述这个类实现了那些接口,这些接口按implements语句从左到右排列在接口缩影集合中。
字段表集合:
- 用于描述接口或类中声明的变量。字段包括类级变量以及实例级变量,但不包括在方法内部声明的局部变量。
- 字段集合不会列出从超类中或者父类接口中继承而来的字段,但有可能列出原本没有的字段,如在内部类中为了保持外部类的访问性会加入外部类的实例字段。
- 字段包含信息:字段的作用域(public、private、protected),是实例变量还是类变量(static修饰符),可变性(final)、并发性(volatile修饰符,是否强制从主内存读写)、可否被序列化(transient修饰符),字段数据类型(基本类型、对象、数组),字段名称。
- 字段修饰符放在access_flag项目中,它包含两项name_index和descript_index,他们都是对常量池的引用,分别代表字段的简单名称和字段的描述符。
- 字段表结构如下图所示:
- 结合之前的常量池中的常量可知类索引为 com/ecut/clazz/TestClass,父类索引为 java/lang/Object。TestClass包含一个被private修饰的int 类型的m。
方法表集合:
- 方法表集合包括访问标志、名称索引、描述符索引、属性集合。如果父类方法在子类方法中没有被重写,方法表集合中不会有来自父类的方法信息。
- 方法表结构如下图:
属性表集合:
- 在class文件中,字段表方法表都可以携带自己的属性表集合,以用于描述某些场景专有的信息。
- 属性集合的结构如下图:
- 结合常量池对文件进行分析可得,方法容量为2包含了两个方法,第一个方法时public修饰void init,该方法包含了一个属性code,code操作数栈最大值为1.第二个方法时public修饰的int inc()该方法也包含了一个属性code。
- Exception属性列举出方法中可能抛出的异常,也就是方法描述时在throws关键字后面列出的异常。
- LineNumberTable属性用于描述Java源码行号和字节码行号之间的对应关系。
- LocalVariableTable属性用来描述栈帧中局部变量与Java源码中定义的变量之间的关系。
- SourceFile属性用来记录生成这个class源码文件名称。
3、字节码指令
概述:
- Java虚拟机的指令由一个字节长度的,代表着某中特定操作含义的数字(称为操作码)以及跟随其后的零至多个代表此操作所需参数(称为操作数)而构成。
- Java虚拟机采用面向操作数栈的架构所以大多数指令都不包含操作数只有一个操作码。
- 在Java虚拟机的指令集中大多数指令都包含了其操作锁对应的数据类型信息。
加载和存储指令:
- 加载存储指令用来将数据在栈帧中的局部变量和操作数栈之间来回传输。
- 将一个局部变量加载到操作数栈iload。
- 将一个数值从操作数栈中存储到局部变量表istore。
- 将一个常量加载到操作数栈bipush。
- 扩充局部变量表的访问索引的指令wide。
运算或算法指令:
- 运算或算法指令用于对两个操作数栈上的值进行某中特定的运算,并把结果重新存入操作数栈的栈顶。
类型转换指令:
- 类型转换指令可以将两种不同的数值类型进行相互转换,这种转换操作一般用于实现用户代码中的显示类型转换操作。
- int——》long——》float——》double。
对象创建和访问指令:
- 虽然类实例和数组都是对象但是使用不同的指令来完成创建。
- 创建类实例的指令 new。
- 创建数组的指令 newarray。
- 访问类字段和实例字段 putfield 、getfield、getstatic。
操作数栈管理指令:
- 将操作数栈的栈顶一个元素出栈pop。
- 将栈顶两个数值交换swap。
控制转移指令:
- 在有条件或者无条件的修改PC寄存器的值。
- 条件分支ifea、iflt。
- 复合条件分支lookupswich。
- 无条件goto 。
方法调用和返回指令:
- 方法调用指令和返回值无关,而方法返回指令是根据返回值类型来区分的。
- invokevirtual用于调用对象的实例方法。
- invokestatic用于调用类方法。
异常处理指令:
- 在Java程序中显示抛出异常的操作都有athrow指令来完成。
- Java虚拟规范还规定许多运行时异常会在其他指令检测到异常时自动抛出。
同步指令:
- Java虚拟机可以支持方法级的同步和方法内部一段指令序列的同步,这两种同步结构都是使用管程(Monitor)来支持的。
推荐博客链接:
https://blog.csdn.net/u010349169/column/info/jvm-principle
转载请于明显处标明出处:
https://www.cnblogs.com/AmyZheng/p/10537013.html
转载于:https://www.cnblogs.com/AmyZheng/p/10537013.html
《深入理解Java虚拟机》读书笔记五相关推荐
- Mysql是怎么运行的读书笔记
前言 第1章 装作自己是个小白–初识Mysql Mysql分为客户端和服务端,客户端有很多种比如:手机 App.桌面端的软件或者网页版的微信.客户端发送请求,服务端处理请求,服务端将处理结果发送客户端 ...
- 《MYSQL是怎样运行的》笔记|配置文件|系统变量|字符集|InnoDB存储结构|数据页结构|索引结构与使用|数据目录|表空间|连表原理|查询优化|BufferPool|事务|redo与undo|锁
<MYSQL是怎样运行的>笔记 前记: 历时15天,笔记+看书.完成于2022.2.5. 本书是讲具体的数据库实现,而数据库系统概念见:https://blog.csdn.net/qq_4 ...
- 《Mysql是怎样运行的》读书笔记五
记录在页中的存储 一个InnoDB数据页的存储空间大致被划分为7个部分,如下面表格所示. 名称 中文名 占用空间大小 简单描述 File Header 文件头部 38字节 页的一些通用信息 Page ...
- 高性能MySQL读书笔记 (五)
1. 优化服务器设置 MySQL有大量的可以修改的参数,但不应该随便修改.应该将更多时间花在schema的优化,索引,查询设计上 配置文件路径: 通常在/etc/my.cnf 不建议动态修改变量,因为 ...
- mysql索引与事务笔记_《MySQL技术内幕:InnoDB存储引擎》读书笔记五-锁、索引及事务...
1.锁mysql 1)锁是数据库系统区别于文件系统的一个关键特性,数据库使用锁是为了支持对共享资源进行并发访问,提供数据的完整性和一致性.算法 2)每一种数据库实现锁的方式都不一样.sql 共享锁:容 ...
- MySQL必知必会读书笔记
第一章 了解SQL 1.1 数据库基础 数据库:保存有组织的数据的容器(通常是一个文件或一组文件).注意要与数据库软件DBMS(数据库管理系统)区别,数据库是通过DBMS创建和操纵的容器.数据库可以是 ...
- 读书笔记——五妹妹的女儿房
最近重读了小说月报2005年第2期原创版上的<五妹妹的女儿房>,作为小说强烈推荐. 当时读完小说时有最初在小说月报上看到<贫嘴张大民的幸福生活>和<天下无贼>的感觉 ...
- 计算机网络读书笔记(五)
链路层 我们将看到两种截然不同的链路层信道,第一种类型是广播信道,这种信道用于连接有线局域网.卫星网和混合光纤同轴电缆接入网中的多台主机.第二种类型的链路层信道是点对点通信链路,这一般应用在长距离链路 ...
- MDX Step by Step 读书笔记(五) - Working with Expressions (MDX 表达式)
1. 大多数表达式会返回数值类型的值,但是也能返回例如字符串,时间,布尔或者其它类型的值. 2. 一般表达式的结果都是几个值通过操作符运算后得到的,下列表格中显示了对比,逻辑的,数值的,字符串以及集合 ...
- Effective Java读书笔记五:异常
第57条:只针对异常的情况才使用异常 异常是为了在异常情况下使用而设计的,不要将它们用于普通的控制流,也不要编写迫使它们这么做的API. 下面部分来自:异常 如果finally块中出现了异常没有捕获或 ...
最新文章
- python调用C++之pybind11入门
- 获取URL中 后面的参数值
- Spring源码追踪3——AOP机制
- MyBatis学习总结(21)——自定义MyBatis Generator插件
- 全国计算机一级word题库,2016全国计算机一级《MS Office》选择题题库
- 华为盒子 鸿蒙,华为盒子真不值得买,网友总结了3个原因
- c++filt识别C++中的函数重载
- Mysql基本语法及其操作(三)
- RabbitMQ之延迟队列
- 解决2021版本idea定位图标消失
- 【NOTE】python3.6下scons运行提示找不到SCons.Script解决方式
- English trip 自习内容 句子结构和成分
- 测试人跳槽~怎么说离职原因新的公司比较能接受?
- 图片如何缩小不降低清晰度?
- 安装allennlp ,使用Elmo
- unity 将图片颜色反转
- 2011-2019,巴塞罗那不相信眼泪
- 基于快速质量图导向法的相位解包裹
- OBc车载充电器 3Kw OBC 车载充电器 含原理图
- 让英文Windows系统支持中文
热门文章
- ipython和anaconda区别_Anaconda和ipython环境适配的实现
- macOS 上的 Charles 配置看一篇就够了
- html如何与py_Web项目如何做单元测试?
- 【收藏备用】服务器基本故障及排查方法
- 带你了解2020年全新【思科专家级认证CCIE】
- 当 K8s 集群达到万级规模,阿里巴巴如何解决系统各组件性能问题?
- 恭喜我的同事丁宇入选年度 IT 领军人物
- 人生苦短,开发用云 | 如何优雅完成程序员的侠客梦?
- php 判断5张牌是不是顺子,从扑克牌中随机抽取5张牌,判断是不是一个顺子,即这5张牌是不是连续(面试题)...
- java8学习_java8学习