diff --git a/jvm/深入理解java虚拟机.md b/jvm/深入理解java虚拟机.md index 5c2f654..0b8e5e5 100644 --- a/jvm/深入理解java虚拟机.md +++ b/jvm/深入理解java虚拟机.md @@ -60,6 +60,18 @@ - [jstat](#jstat) - [jinfo](#jinfo) - [jstack](#jstack) + - [类文件结构](#类文件结构) + - [魔数](#魔数) + - [class文件版本号](#class文件版本号) + - [常量池](#常量池) + - [类索引、父类索引、接口索引集合](#类索引父类索引接口索引集合) + - [字段集合](#字段集合) + - [方法集合](#方法集合) + - [属性表集合](#属性表集合) + - [虚拟机加载机制](#虚拟机加载机制) + - [类加载时机](#类加载时机) + - [加载](#加载) + - [验证](#验证) # 深入理解java虚拟机 @@ -542,3 +554,84 @@ jinfo -sysprops 5338 ### jstack jstack命令用于生成虚拟机当前时刻的线程快照,即当前虚拟机每一个线程正在执行的方法堆栈集合。该命令主要用于定位线程长时间出现停顿的原因,例如线程间死锁、死循环、长时间等待等。 + + +## 类文件结构 +class是以字节为基础单位的二进制流,各个数据项排列紧凑,中间没有分隔符。当数据项实际占用的空间超过一个字节时,多个字节之间按照`大端序`来进行排序,即高位字节在前。 + +class文件采用一种伪结构来存储数据,该伪结构类似C语言中的结构体,伪结构中只有两种数据类型: +- 无符号数: 无符号数属于基本数据类型,u1/u2/u4/u8分别代表长度为1/2/4/8个字节的无符号数,无符号数可以用于描述数字、索引引用、数量值、utf-8编码的字符串值 +- 表:表是由多个无符号数或其他表组成的复合数据类型,所有表都习惯性以`_info`结尾。 + +class文件本质上就是一张表,其组成结构如下所示: +| 类型 | 名称 | 数量 | +| :-: | :-: | :-: | +| u4 | magic | 1 | +| u2 | minor_version | 1 | +| u2 | major_version | 1 | +| u2 | constant_pool_count | 1 | +| cp_info | constant_pool | constant_pool_count -1 | +| u2 | access_flags | 1 | +| u2 | this_class | 1 | +| u2 | super_class | 1 | +| u2 | interfaces_count | 1 | +| u2 | interfaces | interfaces_count | +| u2 | fields_count | 1 | +| field_info | fields | fields_count | +| u2 | methods_count | 1 | +| method_info | methods | methods_count | +| u2 | attributes_count | 1 | +| attribute_info | attributes | attributes_count | + +### 魔数 +每个class文件的头4个字节被称为魔数,其作用是确定该文件是否是一个能被虚拟机接受的class文件。class文件的魔数为`0XCAFEBABE`。 + +### class文件版本号 +魔数之后的4个字节记录的是class文件的版本号: +- 第5、6个字节记录的是minor version(次版本号) +- 第7、8个字节记录的是major version(主版本号) + +jdk的主版本号从45开始,jdk 1.0/1.1使用了45的版本号,而每个jdk大版本发布主版本号都会+1。并且,jdk都能兼容以前版本的class文件。 + +### 常量池 +在class主版本/次版本号之后,是常量池入口。 + +常量池中主要存放字面量和符号引用。 + +### 类索引、父类索引、接口索引集合 +类索引(this_class)和父类索引(super_class)都是一个u2类型的数据,接口索引集合(interfaces)则是一组u2类型的数据集合。 + +class文件通过上述3个字段来确定类的继承关系。 + +### 字段集合 +字段表用于描述接口或类中声明的变量。字段(field)包括类级变量和实例级变量。 + +### 方法集合 +方法集合中同样包含了静态方法和非静态方法。 + +### 属性表集合 +属性表集合用于记录类的一些属性信息,如`final/SourceFile`等。 + +## 虚拟机加载机制 +### 类加载时机 +类从被加载到内存中开始,到类被卸载,其整个生命周期包含如下环节: +- 加载(Loading) +- 验证(Verification) +- 准备(Preparation) +- 解析(Resolution) +- 初始化(Initialization) +- 使用(Using) +- 卸载(Unloading) + +其中,`验证、准备、解析`三个阶段统称为`链接` + +### 加载 +加载是类加载过程中的一个阶段,在加载阶段虚拟机主要执行如下步骤: +- 通过类的全限定类名来获取此类的二进制字节流 +- 将该字节流所代表的静态存储结构转化为方法区的运行时数据结构 +- 在内存中生成一个代表该类的`java.lang.Class`对象,作为方法区中这个类数据的访问入口 + +### 验证 +验证是连接阶段的第一步,这一阶段目的是为了确保class文件中字节流包含信息符合当前虚拟机的要求。 + +