JVM思维导图
2024-03-18 15:21:25 41 举报
AI智能生成
类加载机制 垃圾收集器 JVM内存结构 GC优化
作者其他创作
大纲/内容
父类加载器优先加载,父类无法加载再由子类加载器加载,都加载不到抛出ClassNotFoundException异常
过程
防止内存中出现多份相同字节码
保证java程序稳定安全运行
好处
重写loadClass()方法
破坏模型
双亲委派模型
启动后由JVM初始化加载
Class.forName()加载
ClassLoader.loadClass()加载
类加载方式
将 .class加载到内存中供后续使用
什么是类的加载
加载
验证
准备
解析
连接
初始化
使用
卸载
类的生命周期
加载JDK\\jre\\lib下,或被-Xbootclasspath参数指定的路径且能被虚拟机识别的类库(如rt.jar)
开发者无法直接使用
启动类加载器
加载JDK\\jre\\lib\\ext,或java.ext.dirs系统变量指定的类库
开发者可直接使用
拓展类加载器
加载ClassPath指定的类,默认的类加载器
应用类加载器
定制加载类的方式,继承ClassLoader类,重写findClass() 方法
自定义类加载器
分类
组合关系而而非继承关系
加载器关系
当一个类加载器加载某个类时,该类依赖和引用的其他类也由此类加载器加载,除非显示使用其他类加载器加载
全盘负责
父类加载器优先加载,父类无法加载再由子类加载器加载
父类委托
加载过的类都会被缓存下来
缓存机制
加载机制
类加载器
类加载机制
单线程
最古老、稳定,可能会产生较长停顿
Serial
Serial的多线程版本,其余行为和Serial一样
ParNew
多线程
吞吐量=用户代码运行时间/(用户代码运行时间 + GC时间)
计算公式
-XX:MaxGCPauseMillis 最大垃圾收集停顿时间
-XX:GCTimeRatio 吞吐量大小
开关参数,打开后不需要设置-Xmn、-XX:SurvivorRatio、-XX:PretenureSizeThreshold等细节参数,需要设置基本内存参数(如-Xmx)和优化目标-XX:MaxGCPauseMillis、-XX:GCTimeRatio
-XX:+UseAdaptiveSizePolicy
参数
自适应调节吞吐量
Parallel
年轻代
Serial 的老年代版本
标记整理算法
Serial Old
Parallel的老年代版本
Parallel Old
以获取最小回收停顿时间为目标
标记清除算法
标记GC Roots能直接关联到的对象
初始标记
GC Roots Tracing
并发标记
修正并发标记期间,因用户程序运行过程中标记发生改变的对象的标记记录
重新标记
并发清除
并发收集
低停顿
优
内存碎片
并发阶段降低吞吐量
缺
CMS
老年代
JDK9默认
标记整理、复制算法
将堆划分成多个大小相同的区域(Region)
不存在内存碎片
原理:根据Region回收所需要空间的大小和时间的经验值优先回收价值最大的Region
可预测停顿时间
与CMS比的优势
初始标记,并触发一次Minor GC
Root Region Scanning
再标记
复制/清除
G1
跨代
垃圾收集器
先标记,然后统一清除
标记和清除效率不高
缺点
标记清除
内存划分为相等的两块,将存活对象复制到一块,清理另一块的内存
内存缩小为原来一般
对大量存活的对象复制效率不高
复制算法
先标记,然后将存活对象移动到一段,最后清理掉边界之外的内存
标记整理
年轻代:对象存活率低 —> 复制算法
年老代:对象存活率高,无空间分配担保 —> 标记清除、标记整理
分代收集算法
垃圾收集算法
堆区
方法区
主要工作对象
计数器 > 0, 存活;计数器 = 0, 回收
无法解决对象循环引用的问题
引用计数法
不存在到GC Roots即为不可达
虚拟机栈引用的对象
本地方法栈引用的对象
方法区中类的静态属性引用的对象
方法区中常量引用的对象
GC Roots
可达性分析
对象存活判断
-Xms 堆区最小空间大小
-Xmx 堆区最大空间大小
-XX:NewSize 新生代最小空间大小
-XX:MaxNewSize 新生代最大空间大小
-Xss 每个线程的堆栈大小
-XX:PermSize 永久代空间最小大小
-XX:MaxPermSize 永久代空间最大大小
控制参数
JVM管理的最大内存,GC回收重点,进一步划分为年轻代(Eden区 + 2个Survivor区,Eden:Survivor = 8:1)、年老代
说明
几乎所有对象实例
存储对象
是
是否线程共享
内存无法满足且无法拓展时抛出OOM
异常
有时称为“永久代”(实际上“方法区”是JVM的规范,而“永久代”是规范的一种实现)。回收目标主要是常量池和类型的卸载,回收条件苛刻,回收结果让人难以满意
被JVM加载的类信息、常量、静态变量、即时编译后的代码等
内存无法满足且无法拓展时抛出OOM异常
线程私有,描述的是java方法执行的内存模型,方法执行的过程会创建一个栈帧,方法的执行和退出对应栈帧在JVM栈入栈和出栈的过程
栈帧(局部变量表、方法出入口等信息)
否
超过虚拟机允许的深度抛出StackOverflowError异常
如果可拓展,拓展无法申请到足够内存抛出OOM异常
JVM栈
与JVM栈类似,不过针对的是native本地方法
本地方法栈
记录线程执行的字节码的行号指示器,当线程切换时能恢复到正确位置
计数器
唯一没有OOM的区域
程序计数器
内存划分
对象优先分配在Eden区域。空间不足触发Minor GC
大对象直接进入老年代(避免对大对象复制)。通过参数 -XX:PretenureSizeThreshold 控制对象大小
长期存活的对象进入老年代。通过 -XX:MaxTenuringThreshold 参数控制年龄,每次Minor GC年龄加1
对象动态年龄判断。Survivor区中相同年龄的对象内存总合大于Survivor区的一半,大于等于该年龄的对象进入到老年代
空间分配担保,让Survivor区无法容纳的对象进入老年代。老年代最大可用连续空间是否大于新生代所有对象总和或历次晋升平均大小?是,Minor GC;否,Full GC
对象分配规则
JVM内存结构(JDK7)
监控GC,可使用VisualVM、JProfiler(注:VisualVM可在发生OOM dump出内存使用情况)等软件监控
分析结果,GC发生的时间、频率等(注:在线分析GC日志网站 http://gceasy.io)
调节内存大小、选择垃圾收集器
多个参数结果对比验证
将最佳参数应用到服务器上
通过 -Xms、-Xmx等调优参数将对象尽量留在年轻代
通过 -XX:PretenureSizeThreshold 设置进入老年代对象大小
通过 -XX:MaxTenuringThreshold 设置对象进入老年代年龄,默认15
减少进入老年代的对象
适当减少老年代内存大小(但注意过小会OOM)
选择适合的垃圾收集器
减少Full GC的时间
目的
根源是创建过多的对象
需要减少对象的创建,如StringBuilder代替String、减少不必要日志的输出
GC优化之前
-Xms 初始化堆内存大小
-Xmx 堆内存最大限制
-XX NewSize 年轻代大小
-XX NewRatio 年老代和年轻代内存比
-XX SurvivorRatio Eden区和Survivor区比
常见调优参数
GC优化
JVM
0 条评论
回复 删除
下一页