JVM(三)JVM的执行子系统
2020-05-30 本文已影响0人
7ColorLotus
-
Class文件结构
-
java跨平台的基础
-
Class类的本质
1> Class文件是一组以8位字节为基础单位的二进制流
2> 类似于结构体的伪结构来存储数据
3> 只有两种数据类型:无符号数和表
4> 无符号数属于基本的数据类型,以u1,u2,u4,u8
5> 表是由多个无符号数或者其他表作为数据项构成的符合数据类型 -
Class文件格式详解
1> 魔数与Class文件版本a, java的Class文件魔数:CAFEBABE b, java版本号从45号开始
2> 常量池
a, 字面量:类似于我们常见的常量 b, 符号引用:类和接口的全限定名,字段名称等等,方法的名称等等
3> 访问标志
4> 类索引、父类索引、与接口索引集合
5> 字段表集合
6> 方法表集合
7> 属性表集合
8> javap -verbose xxx.class 查看class文件内容
class文件格式.png
-
-
字节码指令
- 虚拟机所有的指令都是一个字节(0-255),特定的数字表示某种操作,指令数不超过256
- invoke开头的指令都是方法调用指令
- areturn 返回的是一个引用类型,byte,short,char,boolean,int都是i,long 是l
- 指令的分类
1> 加载和存储指令
2> 运算指令
3> 类型转换指令
4> 对象创建与访问指令
5> 操作数栈管理指令
6> 控制转移指令
-
类加载机制
- 加载(Loading)
1> 加载类的二进制流
2> 把静态的存储结构转化为方法区的运行时结构
3> 生成一个代表这个类的class对象 - 连接(Linking)
1>验证(Verification) :检查二进制流是否符合虚拟机的格式
2>准备(Preparation):内存分配
3>解析(Resolution): - 初始化(Initialization): 执行类的构造器。<clinit>不是必须的,而且同时只能有一个线程执行。有且只有5种情况
1> new,getstatic,setstatic,invokestatic
2> 对类进行反射调用
3> 初始化一个类,但是父类还没有初始化的时候,先触发父类的初始化
4> 指定一个执行main的类,应用程序的主类
5> 动态语言支持 - 使用(Using)
- 卸载(Unloading)
- 加载(Loading)
-
类加载器
- 用途:热加载器,代码保护和加密,类层次划分,OSGI等
- 自定义类加载器对类进行加密和解密
- 一个类是否唯一,由这个类本身和加载它的类加载器两个一起决定
- 系统的类加载器
1> 启动类加载器(BootstrapClassLoader) 加载存放在JAVA_HOME\lib目录里的类库,并且是虚拟机识别的类库加载到虚拟机内存中
2> 扩展类加载器(ExtensionClassLoader) 存放在JAVA_HOME\lib\ext目录中的所有类库,开发者可以直接使用
3> 应用程序加载器(ApplicationClassLoader) 加载用户类路径上指定的类库,开发者可以直接使用,一般情况下这个就是程序中默认的类加载器 - 双亲委派模型
1> 双亲委派模型过程:某个特定的类加载器在接到加载类的请求时,首先将加载任务委托给父类加载器,依次递归,如果父类加载器可以完成类加载任务就成功返回;只有父类加载器无法完成此加载任务时,才自己去加载
2> 双亲委派模型好处:Java类随着它的类加载器一起具备了带有优先级的层次关系,保证java程序稳定运行
3> 线程上下文加载器 -
Tomcat类加载机制
Tomcat类加载机制.png
-
栈帧
- 局部变量表:每个局部变量都有一个槽,这个槽可以重用
- 操作栈
- 动态连接
- 返回地址
-
方法调用详解
- 解析:类的静态方法,构造方法,私有方法等在编译期就可以确定
- 分派
1> 静态分派:方法的重载,编译器确定了调用的方法是哪一个
2> 动态分派:类的重写,虚方法表(虚拟机维护,维护着各个方法的实际入口<方法区中的某个地址>,一个类一个方法表)
3> 动态分派的实现
-
基于栈的字节码解释执行引擎
1)基于栈的指令集与基于寄存器的指令集
1> 基于栈的指令集可移植
2> 基于寄存器的指令集,和硬件关系比较紧密,速度快 -
尝试跟着字节码解析代码