深入理解java虚拟机
2022-06-06 13:22:07 0 举报
AI智能生成
深入理解java虚拟机(第三版)
作者其他创作
大纲/内容
准备
词法,语法分析
填充符号表
解析,填充符号表
插入式注解处理器的注解处理过程
分析与字节码生成
javac编译期
擦除式泛型
兼容早期无泛型版本
类型擦除
值类型与未来的泛型
泛型
自动装箱,拆箱 循环遍历
常量if
条件编译
java语法糖
10.前端编译与优化
解释节约内存
编译提升效率
分层编译
解释器预编译器
即时编译器
被多次调用的方法
被多次执行的循环体
栈上替换
热点代码
基于采样的热点探测
hotspot使用
方法调用计数器
回边计数器
热度衰减
基于计数器的热点探测
热点探测
变异对象与触发条件
即使编译占用程序运行时间
占用运算资源
给即时编译做缓存
性能分析制导优化
激进预测性优化
链接时优化
即时编译器优势
提前编译的优劣
提前编译
目标方法复制到调用方法
非虚方法直接内联
虚方法 守护内联
CHA类型继承关系分析
方法内联
支持方法逃逸
不支持线程逃逸
栈上分配
聚合量替换成不可分解的标量
不去创建对象
标量替换
同步消除
一个对象不会逃逸到方法或线程之外
逃逸分析
表达式E计算过,变量值没变化
公共子表达式消除
运行期检查提前到编译器
数组边界检查擦除
编译器优化技术
Graal
11.后端编译与优化
三、程序编译与代码优化
CPU高速缓存
MESI
缓存一致性问题
硬件的效率与一致性
所有变量存在主内存
线程工作内存存副本
主内存和工作内存
lock锁定
unlock解锁
read读取
load载入
use使用
assign赋值
store存储
write写入
子主题
内存间交互
保证可见性
禁止指令重排序
不能保证原子性
volatile
非原子性协定
存2个变量槽
读半个值概率很低
double不会读半个,浮点运算器保证
long和double
read、load、assign、use、store、write保证原子性
新值立即同步到主存
每次使用从主内存刷新
volitile保证可见性
volitile和sychronized保证有序性
原子性,可见性,有序性
线程内,流程控制,代码在前先执行
程序次序规则
unlock先发生lock
管程锁定规则
写先于读
volatile变量规则
Thread的start先于其他所有方法
线程启动规则
线程所有方法先于终止检测
线程终止规则
interrupt()方法先于被中断线程代码检测到中断的发生
线程中断规则
对象初始化先于finalize()
对象终结规则
A先于B,B先于C,则A先于C
传递性
先行发生原则
java内存模型
1:1
内核线程实现
1:N
用户线程实现
M:N
混合实现
java线程直接映射到操作系统原生线程实现
实现线程3种方式
协同式
java使用
抢占式
线程调度
新建
运行
无期限等待
期限等待
阻塞
状态转换
java与线程
有栈协程
无栈协程
执行过程和调度器
调度器:Fork/Join池
纤程
java与协程
12.java内存模型与线程
不可变
绝对线程安全
相对线程安全
线程兼容
线程对立
java语言中的线程安全
临界区 CriticalSection
互斥量 Mutex
信号量 Semaphore
等待可中断
公平锁
可绑定多个条件
ReetrantLock
互斥同步
CAS
非阻塞同步
线程安全实现方式
自旋默认10次
根据同一个锁自旋时间和拥有者状态决定
6自适应自旋
自旋锁与自适应自旋
锁消除
锁粗化
锁优化
不是替代重量级锁
没有多线程竞争前提下,减少重量级锁互斥量的性能消耗
栈帧Lock Record
成功加锁
当前线程指向Lock Record,进入线程
2个线程竞争,变为重量级锁
s失败
CAS尝试更新Mark Word指向 Lock Record
进入同步块,无锁
Mark Work 存储指向调用栈中记录的指针
轻量级锁
目的:消除无竞争下的同步原语
锁会偏向第一个获得它的线程
有竞争力,偏向消失
Mark Work存储偏向线程Id
计算hash无法进入偏向
偏向锁
线程安全
13.线程安全与锁优化
四、高效并发
程序计数器
编译 基本数据 引用指针
局部变量表
方法出口
操作数栈
动态链接
java虚拟机栈
与 java虚拟机栈类似 为native服务
Hotspot中与java虚拟机栈合二为一
本地方法栈
可以划分线程私有缓冲区 TLAB
存储实例对象
堆
类的信息
常量
静态变量
即时编译器后的代码缓存
存储
编译期生成的字面量与符号引用
直接引用
运行时常量池
方法区
存储在内存中的DirectByteBuffer对这块内存进行操作
可以通过NIO,调用Native方法分配内存
不归jvm管理,受到机器内存限制
直接内存
数据运行时数据区
没有,类加载
常量池定位符号引用,检测代表的类是否被加载解析
标记压缩
特点规整
指针碰撞
标记清除
cms这种
空闲列表
Thread Local Allocation Buffer
TLAB
线程预分配缓存
分配内存
对象头
锁相关信息
对对象进行必要设置
对象初始化
执行构造函数
创建
hashCode,对象分代年龄
指向锁记录的指针
指向重量级锁的指针
偏向线程Id,偏向时间戳,对象分代年龄
运行时数据
指向它的类型元数据的指针
类型指针
记录长度
数组
代码里定义的各种类型字段的内容
实例数据
必须是8byte的整数倍
对齐填充
内存布局
栈 reference 堆
对象移动,只移动句柄
句柄
快
指针
主流方式
访问定位
对象
stackOverflowError
栈深度
-Xss
栈溢出
动态代理
jsp
osgi
jdk1.7
方法区运行时常量池溢出
dump没有明显异常
直接内存溢出
outOfMemeryError异常
2.java内存区域与内存溢出异常
引用计数法
本地变量表引用的对象
静态属性引用的对象
常量引用的对象
JNI引用的对象
虚拟机内部 异常 类加载器
锁持有对象
JMXBean,JVMTI回调,本地代码缓存
可达性分析
强
有用非必须
溢出前二次回收
软
非必须
下次垃圾回收
弱
虚
引用类型
F-Queue队列
finalize()方法
生存死亡
废弃常量,
所有类型被回收
类加载器被回收
java.lang.Class没被引用
不使用类型
回收方法区
哪些需要回收-对象已死
记录跨代引用
Remembered Set
速度快
碎片化
标记-清除
实现简单
浪费空间
存活超survivor,进入老年代
分配担保
存活不高
CMS
关注效率
标记-复制
移动式
没有碎片
Parallel
关注吞吐量
标记整理
分代收集理论
什么时候回收-垃圾回收算法
OOPMap
不使用
内存保护陷阱
设置标志位
主动式
特定位置-安全点
不执行代码
安全区域
Card Table实现记忆集
卡页
记忆集和卡表
维护卡表
未脏 更新
为共享
写屏障
根节点枚举
解决:增量更新
出入 黑-》白
G1,Shenandoah
解决:原始快照
删除灰=》白
三色标记
并发的可达性分析
如何回收-hotspot算法实现
单线程
客户端
Serial
Serial并行版本
新生代-复制
老年代-标记整理
UseConMarkSweepGC
配合CMS使用
ParNew
新生代
复制
UseMaxPauseMills
GCTimeRatio
吞吐量优先
Parallel Scavenge
Serial Old
多线程并发
Paralle Old
老年代
stw
初始标记
并发标记
重新标记
并发清除
重置线程
步骤
Full GC
jdk1.5 68
jdk1.6 92
浮动垃圾 Concurrent Mode Failure
jdk9 默认
Collection Set: CSet
1-32M
大对象:超过Region一半
2个TAMS
Region
MaxGcPauseMills
回收比分配慢-》fullgc
修改TAMS
耗时短
并发执行
重新处理SATB
短暂暂停
少量SATB记录
最终标记
Region价值成本排序
STW
存活复制新Region
筛选回收
基于Region
占用10%-20%额外内存
复制+整理
特点
Garbage First
跨代共享:连接矩阵
SATB扫描
组CSet
小stw
没有存活对象Region
并发清理
时间取决于回收集大小
转发指针
cas
读屏障和brooks Pointers
并发回收
就对象引用修正
很短停顿
初始引用更新
时间取决 引用数量
并发引用更新
修正GCRoot引用
最终引用更新
Shenandoah
2M小型
32M中型
不固定大型
Region
并发整理
虚拟内存映射技术
染色指针
Relocation Set 重分配集
决定复制对象
并发预备分配
移动存活对象到Region
为Relocation Set 维护转发表
并发重分配
修正分配集中对象引用
并发重映射
ZGC
垃圾回收器
-XX:PrintGCDetails
-Xlog:gc
垃圾收集日志
不足Minor GC
对象优先在Eden分配
-XX:PretenureSizeThreshold
大对象直接进入老年代
15
-XX:MaxTenuringThreshold
长期存活的对象进入老年代
Survivor年代相同综合大于Suvivor一半
年代大于等于直接进入老年代
对象年龄动态判定
是否允许担保失败
-XX:HandlePromotionFailur
老年代最大连续空间大于晋升平均值
空间分配担保
内存分配与回收策略
3.垃圾收集器与内存分配策略
JMC
商业授权
正式支持
实验性
基础工具
jps
jstat
jinfo
jmap
jhat
jstack
JHSDB
JCconsole
VisualVm
Java Mission Control
可视化工具
HSDIS:Jit生成代码反汇编
HotSpot虚拟机插件和工具
4.虚拟机性能监控,故障处理工具
5.调优案例与分析实战
一、自动内存管理
无符号数
表
魔数与Class文件的版本
常量池
访问标志
类索引、父类索引、接口索引集合
类变量
实例变量
不包含局部变量
字段表集合
方法表集合
属性表集合
Class类文件结构
load
store
加载和存储
add
su
div
rem
运算指令
类型转换指令
字节码指令
6.类文件结构
加载
验证
解析
初始化
使用
卸载
生命周期
类加载时机
全限定名-》字节流
类的Class对象=》方法区
魔数
版本
附加信息
文件格式验证
父类
不允许继承的类
抽象
字段,方法和父类
元数据验证
语义合法
字节码验证
全限定名找到类
方法,字段
修饰符
符号引用验证
静态变量分配初始值
符号引用替换为直接引用
字面量
描述引用的目标
符号引用
指向目标的指针、相对偏移量
类或接口的解析
字段的解析
方法的解析
接口方法的解析
clinit
clinit阻塞
类加载过程
\\lib下
启动类加载器
\\lib\\ext下
扩展类加载器
应用程序类加载器
双亲委派模型
1.2以后出现双亲委派
jdk1.2
JNDI、JDBC、JCE、JAXB、JBI
6ServiceLoader
责任链
SPI
Thread下setContext=ClassLoader
线程上下文类加载器
基础类型回调用户代码
以java.*开头的类,委派给父类加载器加载
否则,将委派列表名单内的类,委派给父类加载器加载
否则,将Import列表中的类,委派给Export这个类的Bundle的类加载器加载
否则,查找类是否在自己的FragmentBundel中,如果在,则委派给F让哥们太 Bundle的类加载器加载
否则,查找Dynamic Import 列表的Bundle,委派给对应的Bundle的类加载器加载
否则,查找失败
OSGI
热部署
破坏双亲委派
类加载器
Jdk9
平台类加载器
应用类加载器
用户自定义类加载
模块化的类加载器
java模块化系统
7.虚拟机类加载机制
存方法参数
局部变量
变量槽
运行期转化为直接引用
退出
异常
方法返回
运行时栈帧
类加载阶段将部分符号引用转为直接引用
依赖静态类型决定方法执行版本
重载
静态分派
重写
运行期确定版本
动态分派
java是静态多分派
动态单分派
方法入口地址
虚方法表提升性能
类型继承关系分析、守护内联、内敛缓存
单分派和多分派
分派
方法调用
类型检查发生在运行期
方法句柄=》MethodHandle
java.lang.invoke
动态调用点
invokedynamic
动态类型语言
解释执行
基于栈的指令集与基于寄存器的指令集
基于栈的解释执行过程
基于栈的字节码解释执行引擎
8.虚拟机字节码执行引擎
部署在同一台服务器上的两个web应用程序类库隔离
部署在同一台服务器上的两个web应用程序类库共享
服务器保证自身安全不受web程序影响
Tomcat:正统的类加载器架构
字节码生成与动态代理
9.类加载及执行子系统的案例与实战
二、虚拟机执行子系统
深入理解java虚拟机
0 条评论
回复 删除
下一页