JVM思维导图
2023-02-01 21:18:19 0 举报
AI智能生成
JVM虚拟机整体知识结构
作者其他创作
大纲/内容
JVM内存模型深度剖析与优化
JVM虚拟机
类装载子系统
运行时数据区(内存模型)
线程共享
堆
年轻代:1/3
Eden:8
minor gc
s0:1
s1:1
老年代:2/3
15次
full gc
方法区(元空间:21M)
常量区
运行时常量池
八大类型常量池
字符串常量池
静态变量
user内存地址,实际对象在堆中
类元信息:代码
元空间满了会扩容,最好是设置256M等,避免无谓的full gc
线程私有
线程栈(多个线程)
栈帧:多个方法多个栈帧,先进后出
局部变量
操作数栈出栈,赋值给局部变量
main方法,局部变量表存的是在堆中math的物理地址
操作数栈:临时存储,cpu寄存器写入,写出
将常量入栈,运算时压入,结果压入
动态链接:符号引用转为直接引用,找符号对应的代码直接地址
方法出口:执行完后返回到哪行代码
本地方法栈:native方法,C++实现,给其他语言调用分配一点内存
程序计数器:行号,内存中的指针位置,线程挂起后可以恢复
字节码执行引擎
从源码级别剖析JVM类加载机制
类加载全过程
windows系统下java.exe调用底层的jvm.dll文件创建C++实现的Java虚拟机
创建一个引导类加载器实例(C++实现)
C++调用Java代码创建JVM启动器实例,该类由引导类加载器负责加载创建其他类加载器
sun.misc.Launcher.getLauncher()
获取运行类自己的类加载器ClassLoader,AppClassLoader实例
launcher.getClassLoader()
加载
在硬盘上查找并通过IO读入字节码文件,使用到类时才会加载,例如调用类的main()方法,new对象等等,
在加载阶段会在内存中生成一个代表这个类的java.lang.Class对象,作为方法区这个类的各种数据的访问入口
在加载阶段会在内存中生成一个代表这个类的java.lang.Class对象,作为方法区这个类的各种数据的访问入口
验证
校验字节码文件的正确性
准备
给类的静态变量分配内存,并赋予默认值
解析
将符号引用替换为直接引用,该阶段会把一些静态方法(符号引用,比如main()方法)替换为指向数据所存内存的指针或者句柄等(直接引用),这是所谓的静态链接过程(类加载期间完成),动态链接是在程序运行期间完成的将符号引用替换为直接引用
初始化
对类的静态变量初始化为指定的值,执行静态代码块
使用
卸载
调用loadClass方法加载要运行的类,也就是Math
classLoader.loadClass("Math")
加载完成时候JVM会执行Math类的main方法入口
Math.main()
java程序运行结束
JVM销毁
类加载器
引导类加载器
负责加载支撑JVM运行的位于JRE的lib目录下的核心类库,比如rt.jar、charsets.jar等
扩展类加载器
负责加载支撑JVM运行的位于JRE的lib目录下的ext扩展目录中的JAR类包
应用程序类加载器
负责加载ClassPath路径下的类包,主要就是加载你自己写的那些类
自定义加载器
负责加载用户自定义路径下的类包
重写findClass方法
双亲委派机制
过程
检查一下指定名称的类是否已经加载过,如果加载过了,就不需要再加载,直接返回
如果此类没有加载过,那么,再判断一下是否有父加载器;如果有父加载器,则由父加载器加载
(即调用parent.loadClass(name, false);).或者是调用bootstrap类加载器来加载。
(即调用parent.loadClass(name, false);).或者是调用bootstrap类加载器来加载。
如果父加载器及bootstrap类加载器都没有找到指定的类,那么调用当前类加载器的findClass方法来完成类加载
一句话总结
双亲委派机制说简单点就是,先找父亲加载,不行再由儿子自己加载
为什么要设计双亲委派机制
沙箱安全机制:自己写的java.lang.String.class类不会被加载,这样便可以防止核心API库被随意篡改
避免类的重复加载:当父亲已经加载了该类时,就没有必要子ClassLoader再加载一次,保证被加载类的唯一性
全盘负责委托机制
“全盘负责”是指当一个ClassLoder装载一个类时,除非显示的使用另外一个ClassLoader,该类所依赖及引用的类也由这个ClassLoder载入。
打破双亲委派机制
重写类加载方法,实现自己的加载逻辑,不委派给双亲加载
Hotspot源码JVM启动执行main方法流程图
垃圾收集器ParNew&CMS与底层三色标记算法
垃圾收集算法
分代收集算法
标记-复制算法
标记-整理算法
标记-清除算法
垃圾收集器
Serial收集器
串行收集器
单线程
工作时暂停其他所有工作线程,Stop The World
新生代采用复制算法
老年代采用标记-整理算法
没有线程交互的开销单线程收集效率高,简单而高效
Parallel Scavenge收集器
Serial收集器的多线程版本
吞吐量高,高效利用CPU
新生代采用复制算法
老年代采用标记-整理算法
JDK8默认的新生代和老年代收集器
ParNew收集器
与Parallel Scavenge收集器
CMS收集器
CMS(Concurrent Mark Sweep)收集器是一种以获取最短回收停顿时间为目标的收集器。
标记-清除算法实现过程
初始标记
并发标记
重新标记
并发清理
并发重置
优点
并发收集
低停顿
缺点
对CPU资源敏感(会和服务抢资源)
无法处理浮动垃圾(在并发标记和并发清理阶段又产生垃圾,这种浮动垃圾只能等到下一次gc再清理了
它使用的回收算法-“标记-清除”算法会导致收集结束时会有大量空间碎片产生,当然通过参数-
XX:+UseCMSCompactAtFullCollection可以让jvm在执行完标记清除后再做整理
XX:+UseCMSCompactAtFullCollection可以让jvm在执行完标记清除后再做整理
执行过程中的不确定性,会存在上一次垃圾回收还没执行完,然后垃圾回收又被触发的情况,特别是在并
发标记和并发清理阶段会出现,一边回收,系统一边运行,也许没回收完就再次触发full gc,也就是"concurrent
mode failure",此时会进入stop the world,用serial old垃圾收集器来回收
发标记和并发清理阶段会出现,一边回收,系统一边运行,也许没回收完就再次触发full gc,也就是"concurrent
mode failure",此时会进入stop the world,用serial old垃圾收集器来回收
核心参数
1. -XX:+UseConcMarkSweepGC:启用cms
2. -XX:ConcGCThreads:并发的GC线程数
3. -XX:+UseCMSCompactAtFullCollection:FullGC之后做压缩整理(减少碎片)
4. -XX:CMSFullGCsBeforeCompaction:多少次FullGC之后压缩一次,默认是0,代表每次FullGC后都会压缩一
次
5. -XX:CMSInitiatingOccupancyFraction: 当老年代使用达到该比例时会触发FullGC(默认是92,这是百分比)
6. -XX:+UseCMSInitiatingOccupancyOnly:只使用设定的回收阈值(-XX:CMSInitiatingOccupancyFraction设
定的值),如果不指定,JVM仅在第一次使用设定值,后续则会自动调整
7. -XX:+CMSScavengeBeforeRemark:在CMS GC前启动一次minor gc,目的在于减少老年代对年轻代的引
用,降低CMS GC的标记阶段时的开销,一般CMS的GC耗时 80%都在标记阶段
8. -XX:+CMSParallellnitialMarkEnabled:表示在初始标记的时候多线程执行,缩短STW
9. -XX:+CMSParallelRemarkEnabled:在重新标记的时候多线程执行,缩短STW;
2. -XX:ConcGCThreads:并发的GC线程数
3. -XX:+UseCMSCompactAtFullCollection:FullGC之后做压缩整理(减少碎片)
4. -XX:CMSFullGCsBeforeCompaction:多少次FullGC之后压缩一次,默认是0,代表每次FullGC后都会压缩一
次
5. -XX:CMSInitiatingOccupancyFraction: 当老年代使用达到该比例时会触发FullGC(默认是92,这是百分比)
6. -XX:+UseCMSInitiatingOccupancyOnly:只使用设定的回收阈值(-XX:CMSInitiatingOccupancyFraction设
定的值),如果不指定,JVM仅在第一次使用设定值,后续则会自动调整
7. -XX:+CMSScavengeBeforeRemark:在CMS GC前启动一次minor gc,目的在于减少老年代对年轻代的引
用,降低CMS GC的标记阶段时的开销,一般CMS的GC耗时 80%都在标记阶段
8. -XX:+CMSParallellnitialMarkEnabled:表示在初始标记的时候多线程执行,缩短STW
9. -XX:+CMSParallelRemarkEnabled:在重新标记的时候多线程执行,缩短STW;
垃圾收集底层算法实现
三色标记
黑色
表示对象已经被垃圾收集器访问过, 且这个对象的所有引用都已经扫描过。 黑色的对象代表已经扫描
过, 它是安全存活的, 如果有其他对象引用指向了黑色对象, 无须重新扫描一遍。 黑色对象不可能直接(不经过
灰色对象) 指向某个白色对象
过, 它是安全存活的, 如果有其他对象引用指向了黑色对象, 无须重新扫描一遍。 黑色对象不可能直接(不经过
灰色对象) 指向某个白色对象
灰色
表示对象已经被垃圾收集器访问过, 但这个对象上至少存在一个引用还没有被扫描过
白色
表示对象尚未被垃圾收集器访问过。 显然在可达性分析刚刚开始的阶段, 所有的对象都是白色的, 若
在分析结束的阶段, 仍然是白色的对象, 即代表不可达。
在分析结束的阶段, 仍然是白色的对象, 即代表不可达。
浮动垃圾
在并发标记过程中,如果由于方法运行结束导致部分局部变量(gcroot)被销毁,这个gcroot引用的对象之前又被扫描过
(被标记为非垃圾对象),那么本轮GC不会回收这部分内存
(被标记为非垃圾对象),那么本轮GC不会回收这部分内存
漏标-读写屏障
漏标会导致被引用的对象被当成垃圾误删除
解决方案
增量更新(Incremental
Update)
Update)
和原始快照(Snapshot At The Beginning,SATB)
读写屏障,以Java HotSpot VM为例,其并发标记时对漏标的处理方案
CMS:写屏障 + 增量更新
G1,Shenandoah:写屏障 + SATB
ZGC:读屏障
记忆集与卡表
记录集(Remember Set)
在新生代做GCRoots可达性扫描过程中可能会碰到跨代引用的对象,这种如果又去对老年代再去扫描效率太低了。
为此,在新生代可以引入记录集(Remember Set)的数据结构(记录从非收集区到收集区的指针集合)
为此,在新生代可以引入记录集(Remember Set)的数据结构(记录从非收集区到收集区的指针集合)
卡表(cardtable)
卡表是使用一个字节数组实现:CARD_TABLE[ ],每个元素对应着其标识的内存区域一块特定大小的内存块,称为“卡
页
页
卡页:hotSpot使用的卡页是2^9大小,即512字节
垃圾收集器G1&ZGC详解
G1收集器
针对多颗处理器以及大内存的机器,满足GC停顿时间短,高吞吐
Region[ˈriːdʒən]:区域
JVM最多2048个
大小为 堆内存/2048
年轻代 5% 8 1 1
新生代最多不超过60%
Humongous
大对象Region
超过一个region的50%判定为大对象
一次GC运作过程
初始标记
并发标记
最终标记
筛选回收
特点
并行与并发
分代收集
空间整合
可预测停顿
垃圾收集分类
YoungGC
MixedGC
Full GC
适合使用的场景
50%以上的堆被存活对象占用
对象分配和晋升的速度变化非常大
垃圾回收时间特别长,超过1秒
8GB以上的堆内存(建议值)
停顿时间是500ms以内
ZGC收集器
JDK 11中新加入的具有实验性质的低延迟垃圾收集器
ZGC目标
支持TB量级的堆
最大GC停顿时间不超10ms
奠定未来GC特性的基础
最糟糕的情况下吞吐量会降低15%
ZGC的Region
小型Region(Small Region) : 容量固定为2MB, 用于放置小于256KB的小对象。中
中型Region(Medium Region) : 容量固定为32MB, 用于放置大于等于256KB但小于4MB的对象。
大型Region(Large Region) : 容量不固定, 可以动态变化, 但必须为2MB的整数倍, 用于放置4MB或
以上的大对象
以上的大对象
颜色指针:Colored Pointers 每个对象有一个64指针
前18位:预留给以后使用
1位:Finalizable标识,此位与并发引用处理有关,它表示这个对象只能通过finalizer才能访问
1位:Remapped标识,设置此位的值后,对象未指向relocation set中(relocation set表示需要GC的
Region集合)
Region集合)
1位:Marked1标识
1位:Marked0标识,和上面的Marked1都是标记对象用于辅助GC
42位:对象的地址(所以它可以支持2^42=4T内存):
优势
一旦某个Region的存活对象被移走之后,这个Region立即就能够被释放和重用掉,而不必等待整个堆中所有指
向该Region的引用都被修正后才能清理,这使得理论上只要还有一个空闲Region,ZGC就能完成收集
向该Region的引用都被修正后才能清理,这使得理论上只要还有一个空闲Region,ZGC就能完成收集
颜色指针可以大幅减少在垃圾收集过程中内存屏障的使用数量,ZGC只使用了读屏障
颜色指针具备强大的扩展性,它可以作为一种可扩展的存储结构用来记录更多与对象标记、重定位过程相关的数
据,以便日后进一步提高性能
据,以便日后进一步提高性能
读屏障
ZGC运作过程
并发标记
并发预备重分配
并发重分配
并发重映射
Java调优实战
Arthas:阿里巴巴开源的java诊断工具
Class常量池:class文件中
字面量
数字
字符串
符号引用
类和接口的全限定名
字段的名称和描述符
方法的名称和描述符
运行时常量池:在堆中
直接赋值字符串
new String();
intern方法
0 条评论
下一页