JVM虚拟机复习
2021-04-04 00:24:07 1 举报
AI智能生成
登录查看完整内容
参考书籍:深入理解JVM虚拟机第三版
作者其他创作
大纲/内容
JVM虚拟机
运行时数据区
字节码的行号指示器:控制程序的分支,循环,跳转
方法的调用返回:进栈与出栈
存储加载的类信息等
方法区
JDK1.7
JDK1.8移除永久代,并移除字符串常量池,静态变量等信息到java堆中
永久代
元空间
运行时常量池
字面量
符号引用
本地方法栈
虚拟机栈
栈针
局部变量表
操作数栈
动态链接
返回地址
程序计数器
堆
分代
新生代
Eden空间
2个Survivor空间
老年代
Eden和Survivor默认比例8:1
非分代
Region
新生代和老年代默认比例1:2
直接内存
java对象
内存分配
指针碰撞
空闲列表
连续空间分配,带压缩整理的收集器,Serial,ParNew
空间不连续,基于清除算法的收集器,CMS
指针修改
CAS重试保证原子性
本地线程分配缓冲TLAB
预先分配一小块连续的内存
对象的内存布局
对象头
指向它的类型元素的指针,确定该对象是哪个类的实例
MarkWord
01:未锁定,可偏向
对象hash码,对象分代年龄
偏向线程ID,对象分代年龄
无锁
偏向锁
00:轻量级锁定
10:重量级锁
11:GC标记
指向所记录的指针:锁记录存储在当前线程栈针中
指向重量级锁的指针,monitor
类型指针
实例数据
对齐填充
对象的访问定位
句柄
直接指针
性能监控和故障处理工具
命令工具
jps
jstat
jinfo
jmap
jstack
查看虚拟机进程:jps -mlv
虚拟机统计信息监视工具:jstat -gcutil pid 250 20:每250毫秒查一次,总共查20次
查询jvm隐式的默认参数,jps查看显示指定的参数
生成堆的快照文件,jmap -dump显示堆的详细信息,jmap -heap
查询线程快照,jstack -l pid
启动参数指定
打印详细的GC信息
查看GC前后堆,方法区的容量变化
查看用户线程并发时间
查询用户线程停顿时间
查询自适应相关信息
查看收集过后剩余对象年龄分布
发生内存溢出后自动生成堆快照文件
查看安全点信息,是否有线程卡住无法进入安全点
进入安全点超过2s为超时,打印超时线程
-XX:PrintGCDetails
-XX:PrintHeapAtGC
-XX:PrintGCApplicationConcurrentTime
-XX:PrintGCApplicationStopTime
-XX:PrintAdaptiveSizePolicy
-XX:PrintTenuringDistribution
-XX:HeapDumpOnOutOfMemoryError
-XX:PrintSafepointStatistics
可视化工具
JConsole
VisualVM
JMC
飞行记录
常见故障原因
垃圾回收时间短,但用户停顿时间长
堆大小不合理,设置太大导致每次回收的垃圾巨多,GC时间长,停顿时间长
堆外内存溢出
大对象,在年轻代来回复制,导致MinorGC时间长
线程卡住,无法进入安全点
垃圾收集原理
标记垃圾
无法解决循环引用的问题
垃圾回收时被调用,如果有重写会被加入到F-Queue中进行重新标记,如果在重写的方法中将对象引用再次赋值则会逃脱被收集
引用计数法
可达性分析
GC root
虚拟机栈中引用的对象
静态属性应用的对象
常量引用的对象
本地方法栈Native中引用的对象
java虚拟机内部的引用
同步锁持有的对象
跨代引用
基本数据类型对应的Class对象,异常对象,类加载器
收集年轻代时,老年代有对象引用了年轻代的对象
引用类型
引用赋值
有用非必须的对象,在发生内存溢出前进行回收
只能生存到下一次垃圾收集发送为止
无法通过虚引用来取得对象的实例,对象再被系统回收时收到系统通知
强引用
软引用
弱引用
虚引用
finalize()
垃圾回收算法
标记-清除
1、标记需要清除的对象
2、清除对象
存在的问题
大量对象需要被标记然后清除,效率低
产生大量内存碎片
标记-复制
1、标记存活的对象
2、复制存活的对象到另一块区域
空间的浪费
剩余存活的对象不足以放入空闲空间,需要进行分配担保
标记-整理
2、将存活的对象移动到内存的一端
移动大量存活对象并更新引用比较耗时,Stop The World时间长
解决了内存碎片的问题
内存分配与回收策略
优先分配在Eden区
大对象直接进入老年代
长期存活的对象进入老年代
动态对象年龄判定
空间分配担保
1、MinorGC之前,先判断老年代空闲连续空间大小是否大于新生代所有对象占用空间
2、大于则直接进入老年代
3、小于则看是否允许担保,无担保直接FullGC,有担保则看历代晋升到老年代对象的大小是否小于老年代剩余空间,小于则MinorGC,否则FullGC
-XX:PretenureThreshold,仅对Serial和ParNew有效
-XX:MaxTenuringThreshold,默认15
Survivor空间中相同年龄对象大小总和大于Survivor空间一半,则年龄大于等于此相同年龄的对象直接进入老年代
HotSpot算法细节
枚举跟节点
安全点
抢占式中断
主动式中断
先中断,发现有程序没有到达安全点再恢复执行,知道跑到安全点
设置标志位,达到安全点检查标志位,如果需要中断则停下来
安全区域
记忆集与卡表
写屏障
先判断是否有被标记过,未被标记才将其变脏
记录原始快照
增量更新,维护卡表
写前屏障
写后屏障
伪共享问题
并发可达性分析
消亡的对象标记为存活
存活的对象标记为消亡
先标记为存活,在标记剩下的其他对象是,原本存活对象的引用断开,这种情况可以在下次收集时清除掉,问题不大
在还未标记到该存活对象是,引用断开,然后再与已经标记完的对象连接起来,导致垃圾回收时被清除掉
解决方案
增量更新CMS
原始快照G1,Shenandoah
新增对象时,将新增的引用关系记下来,并发扫描结束后再处理这部分新增的对象
将删除的引用关系记下来,并发扫描结束后在重新扫描删除的引用关系,也就是说以开始扫描时的引用关系快照为准
必须停顿,OopMap加速枚举,OopMap存储了引用信息,例如栈里面哪些位置是引用
什么地方生成OopMap?长时间执行的特征,例如方法调用,循环跳转,异常跳转
线程阻塞,无法继续执行到安全点,但此时引用关系不会发送变化,即安全区域
针对老年代,字节数组,每个元素标志着一块内存区域,存在跨带指针标识为1,否则为0
赋值操作,维护卡表,增量更新,原始快照有用到
垃圾回收器
新生代垃圾回收器
Serial
ParNew
Parallel Scavenge
停顿时间设置-XX:MaxGCPauseMillis
吞吐量设置-XX:GCTimeRatio
自适应策略-XX:UseAdaptiveSizePolicy
单线程
多线程
多线程,可控制吞吐量
老年代垃圾回收器
Serial Old
Parallel Old
CMS
如果产生的浮动垃圾不足以放在老年代则触发备选方案Serial Old
回收线程数(处理器核心数量+3)/4
无法找到足够大的连续空间存放对象则触发FullGC进行整理
处理过程
初始标记
并发标记
重新标记
并发清除
短暂停顿
处理增量更新产生的引用关系,也需要短暂停顿
标记-清除,由于不需要移动对象改变引用,所以可以和用户线程并行
记录增量更新
浮动垃圾
JDK5中老年代使用率达到68%触发GC
JDK6中老年代使用率达到92%触发GC
碎片空间
多线程,吞吐量优先
混合垃圾回收器
G1
区域划分
每个Region都可以扮演多个角色,Eden,Survivor,老年代
专门存放大对象,超过Region一半则是大对象,超大对象被存放在N个连续的Humongous
Humongous
可预测停顿时间
双向卡表
并发标记引用变化处理方式
原始快照
两个TAMS指针
存放新增的对象,同样存在内存回收速度赶不上分配速度的情况,需要冻结用户线程进行FullGC,并行GC
最终标记
筛选回收
标记GC Root,修改TAMS指针
记录原始快照变化的引用
处理原始快照的引用
对Region进行排序,选择性回收,复制到新的Region,修改引用清除旧Region
需要维护双向卡表,占用资源多,将写屏障操作异步进行
对每个Region进行价值计算,优先回收价值高的Region,-XX:MaxGCPauseMillis
每个Region维护一个双向卡表,分别记录了本Region的脏卡和其他Region指向本Region的脏卡索引号
Shenandoah
相比于G1,Shenandoah去掉了双向卡表,使用连接矩阵减少维护的消耗
在并发回收的过程了,如果访问到了旧对象需要根据转发指针进行一次转发,使用读屏障进行转发
区域划分同G1一致
连接矩阵
并发回收
初始引用更新
并发引用更新
最终引用更新
并发清理
标记GC Root
处理原始快照,得到Region价值最高的回收集
复制对象到新的Region,CAS修改旧对象的转发指针
确认收集线程已完成对象的移动任务,会短暂停顿
将引用指向新对象,按照物理内存线性搜索引用类型进行更新
修改GC Root的引用,短暂停顿
清理旧Region
读屏障
ZGC
每次回收扫描所有Region,因此没有跨代一说,也就没有写屏障
小型Region
中型Region
大型Region
固定容量2M,存放小于256K的小对象
固定容量32M,存放大于等于256K但小于4M的对象
容量不固定,可以动态变化,用于放置4M以上的大对象,每个Region只放1个对象,容量可能小于中型Region
染色指针
64位寻址地址:其中18位不能用,46位用来寻址,取4位来做染色标记,42位用来寻址,所以ZGC暂时只支持4TB的内存寻址,即ZGC能管理的最大内存是4TB
取引用指针可用来寻址的高4位来表示对象的状态
染色指针可以使得某个Region中的存活对象被移走后,这个Region立即就能释放
染色指针可以大幅减少垃圾收集过程中内存屏障的使用,因为指针维护了相关信息
染色指针可扩展性强,寻址地址中还有18位并为使用
地址多重映射,将多个不同的虚拟地址映射到同一个物理地址上,因为有4位拿来做其他标记,同一个物理地址的指针可能存在多种状态
在指针上面做标记,给指针染色,使用了Marked0和Marked1标志位
统计出本次收集需要清理的Region构成重分配集,大型Region不会被重分配
修改旧引用指针指向新对象,合并到下一次并发标记中处理,减少遍历对象图的开销
并发预备重分配
并发重分配
1、将重分配集中的对象复制到新的Region,并给每个重分配集中的Region维护一个转发表
2、访问时从指针上就可以判断是否要转发,由读屏障根据Region的转发表转发到新对象上
3、首次转发后,同时修改引用值,使指针指向新对象,称为指针的自愈能力
4、由于染色指针的存在,Region复制完成后就可以清除掉,后面访问通过转发表进行转发
并发重映射
0 条评论
回复 删除
下一页