深入理解Java虚拟机
2019-07-12 09:55:06 0 举报
AI智能生成
深入理解java虚拟机 读书导图 方便复习 有错误持续更新
作者其他创作
大纲/内容
Jvm内存分配
堆内存
永久代 PerGem
jdk1.8前
存在虚拟机中,使用String.intern()可直接内存爆炸
jdk1.8后
存在元空间中,即机器内存,不放在虚拟机内 (Metaspace)
老年代
新生代
Eden
Survivor
from
to
方法区
存放类信息 常量 静态变量 即时编译器编译后的代码等
虚拟机栈
局部变量表(通过索引定位)
操作栈
算数运算
调用方法时参数传递
动态链接
返回地址
正常退出,把执行的返回值压入操作栈,再返回计数器的值
异常退出,通过异常表确定返回值
其他附加信息
本地方法栈
程序计数器
解释器通过改变计数器的值来选取下一条执行的指令,分支 循环 跳转 异常都需要依赖计数器完成
执行本地方法时为null
Java类(class文件)
数据结构
无符号数
数字
索引引用
数量值
Utf-8构成字符串
索引引用
数量值
Utf-8构成字符串
表
文件主体
头
魔数
次版本号(Minor Version)
主版本号(Major Version)
常量池
常量池入口 记录容量
常量池内容的类型包含
字面量
符号引用
类和接口的全限定名
字段的名称和描述符
方法的名字和描述符
数据结构:使用 "表" 结构存储
入口
14种不同常量类型
访问标志
类索引
父类索引
接口集合
入口
字段表
入口
访问标志
访问级别
是否类变量(static)
并发可见性(volatile)
可否被序列化(transient)
是否枚举
是否可变
简单名(索引值)
字段描述(索引值)
其他属性数量
属性值
方法表
入口
访问标志
访问级别
是否类方法(static)
是否final
是否同步(synchornized)
是否编译器生成的桥接方法
是否接受不定参数
是否native
是否abstract
是否strictfp
是否编译器自动产生
简单名(索引值)
字段描述(索引值)
其他属性数量
属性值
属性表集合
名称索引
属性长度
属性内容
属性名:Code
max_stack
操作数栈深度的最大值(jvm根据这个分配栈帧)
max_locals
描述局部变量表所需要的存储空间
code_length
该方法字节码长度
code
虚拟机执行的代码
exception_talbe_length
异常处理表的长度
exception_talbe
异常处理表
start_pc
end_pc
handler_pc
catch_type
内联属性
attributes_count
attributes
属性名:Exception
声明抛出的异常
属性名:LineNumberTable
与Java源码的偏移量
属性名:LocalVariableTable
标识局部变量表中变量与java源码的关系
属性名:SourceFile
记录源码文件名
属性名:ConstantValue
通知虚拟机为静态变量赋值
属性名:InnerClass
内部类与宿主类的关联
属性名:Deprecated
标识方法或字段或类不推荐使用
属性名:Synthetic
标识方法由编译器生成
属性名:StackMapTable
验证使用
属性名:Signature
记录泛型类型
属性名:BootstrapMethods
用户保存 invokedynamic指令引用的引导方法限定符
类加载机制
加载
通过类的全限定名获取定义此类的二进制流
二进制流转化为方法区的运行时数据结构
在内存中生成一个代表该类的java.lang.Class对象
数组类型不通过类加载创建,但是具体类还是需要加载
如果组件类型是引用,则递归去加载
如果组件类型是基本类型,则标记为与引导类加载器关联
数组可见性与组件类型一致,若组件是基本类型,默认public
在内存中实例化一个java.lang.Class对象存放本次加载的类
验证
文件格式验证
魔数验证
主次版本号验证
检查常量池tag标志范围
常量索引值是否存在
constant_uft8_info 型中是否有不符合utf-8规则的数据
字节码文件是否有缺失或附加其他信息
元数据验证
是否有父类
父类是否final等
是否实现了抽象父类或接口要求实现的方法
字段 方法是否与父类矛盾
字节码验证
保证任意时刻操作数栈与指令代码序列能配合工作
保证指令跳转不会跳出方法体以外
保证方法体内类型转换有效
符号引用验证
符号中引用的字符串描述全限定名能否找到对应的类
指定类是否存在符合的方法名与字段
访问的字段,类,方法的访问权限是否合法
准备
初始化类变量(static)
初始化是内存置零(引用置null)的工作,并非初始化程序定义的值
final static 的值会被初始化,对应字段的属性ConstantValue指向初始化的值
解析
引用的相关类解析
类型
数组类型
先加载类,再生成代表数组维度和元素的数组对象
非数组类型
传给该类的类加载器去加载该类
解析目标
静态不可变的
静态方法
私有方法
字段解析
解析类后,匹配简单名称跟字段描述符都符合,则返回直接引用
上面不成立,若实现了接口,则自下而上递归父接口
上两个都不成立且不是Object类,则自下而上继续寻找父类
都不成立,抛NoSuchFieldError
类方法解析
类方法与接口方法是分开的,如果混用则抛IncompatibleClassChangeError
解析类后,匹配简单名称跟类方法描述符都符合,则返回直接引用
上面不成立,则递归父类寻找
上两个不成立,则递归接口列表以及父类接口,如果存在匹配,则抛AbstractMethodError
都不成立,抛NoSuchMethodError
接口方法解析
类方法与接口方法是分开的,如果混用则抛IncompatibleClassChangeError
解析接口后,匹配简单名称跟接口方法描述符都符合,则返回直接引用
上面不成立,则递归查找父接口
都不成立,抛NoSuchMethodError
初始化<clinit>
编译器收集类的赋值以及静态语块
jvm保证执行子类的clinit时父类的clinit已经执行完毕
非必须,若类不存在静态赋值与静态块,则不会生成clinit方法
接口不需要先执行父类的clinit,只有当父类的字段被使用,才开始初始化. 接口的实现类也是
执行clinit的时候是阻塞的,会被加锁
使用
卸载
类加载器
类加载器
启动类加载器
负责加载在%javaHome/lib 目录中的类还有-Xbootclasspath指定路径的
无法被java程序直接引用,重写的类加载器需要委派给启动类,则返回null即可
扩展类加载器
负责%javaHome/lib/ext目录与被java.ext.dirs系统变量指定路径的所有类库
应用程序类加载器
负责加载用户类的路径(ClassPath)
双亲委派模型
递归往父类加载器寻找类,直到所有父类都无法加载为止
垃圾收集
垃圾收集理论
垃圾分析算法
引用计数算法
可达性分析算法
引用分类
强引用
软引用
弱引用
虚引用
垃圾收集算法
标记清除
复制算法
标记整理算法
分代收集算法
老年代
新生代
Stop the World算法
抢先式中断
主动中断式
垃圾收集器实现
Serial收集器
Serial Old 老年代收集器
ParNew收集器
老年代收集器
Parallel Scavenge收集器
Parallel Old 老年代收集器
CMS收集器
初始标记
并发标记
重新标记
并发清除
G1收集器
初始标记
并发标记
最终标记
筛选回收
Java对象 内存模型
对象头
运行时数据[Mark Word]
哈希码
GC分代年龄
锁状态标志
线程持有的锁
偏向线程ID
偏向时间戳
对象类型指针
实例数据
对齐填充
Jvm并发安全
规定原子性操作
volatile关键字
保证了变量可见性
禁止指令重排
happens-before规则
程序次序规则
管程锁定规则
volatile变量规则
线程启动规则
线程终止规则
线程中断规则
对象终结规则
传递性
锁优化
自旋锁
锁消除
锁粗化
轻量级锁
偏向锁
字节码指令(ISA)
加载与存储指令
运算指令
类型转换指令
对象创建于访问指令
操作数栈管理指令
控制转移指令
方法调用和返回指令
异常处理指令
同步指令
字节码执行引擎
方法调用
解析
动态可变(invokedynamic指令)
分派
静态分派
静态类型 Human = new Man() Human就是静态类型
类型自动转换
1 精确基本类型
2 char>int>long>float>double
3 自动封箱(精准类型的封箱,不会跨类型,如char 不会转 Integer)
4 找到自动封箱的接口类型(存在同级接口重载,则会拒接编译)
5 Object
6 可变长参数
动态分派
执行代码定位
1 定位对象实际类型
2 准确匹配方法
3 否则递归父类查找
4 都不成立则抛AbstractMethodError 成立则返回方法引用
方法定位实际实现
虚方法表/接口方法表
MethodHandler
与反射的区别
1 反射是在代码层,而MethodHandler是在字节码层
2 反射包含很多信息,包括类信息权限等
3 虚拟机会对MethodHandler进行优化
静态不可变
在类加载时完成解析
static
private
final
执行引擎
编译流程
源码>词法分析>单词流>语法分析>抽象语法树(AST)
指令流>解释器>解释执行
优化器>中间代码>生成器>目标代码
虚拟机栈
局部变量表(通过索引定位)
操作栈
算数运算
调用方法时参数传递
动态链接
返回地址
正常退出,把执行的返回值压入操作栈,再返回计数器的值
异常退出,通过异常表确定返回值
其他附加信息
数据基本类型
堆中1字节
boolean
byte
堆中2字节
char
short
堆中4字节
int
float
reference
jvm规范中没指定大小,但是必须能明确指定两个地址
1.归属类型地址指定
2.堆地址指定
returnAddress
堆中8字节
long
double
收藏
收藏
0 条评论
下一页