JVM
2025-07-18 15:27:35 0 举报
包括类加载,JVM内存模型,垃圾回收算法及垃圾回收器
作者其他创作
大纲/内容
javac源代码编译器
逃逸分析判断一个对象的引用是否“逃出”当前方法或线程。结果分类:无逃逸:只在方法内使用线程逃逸:在多线程中被共享方法逃逸:传给了别的方法或赋值给全局变量➡️ 作用:为后续的优化做基础(栈上分配、锁消除等)
解析
编译
垃圾回收算法
软引用:通过SoftReference创建出来的对象是软引用,内存充足时,不会被回收,只有内存不足时,才会回收。常用来做缓存
机器码指令
将热点代码编译为机器码,执行更快
字段信息
步骤:1.标记 通过可达性算法标记所有存活对象 2.清除:统一回收不可达对象
存储计算过程中的中间结果(用于字节码指令执行)
MarkWord
堆
即时编译器JIT
本地方法库
实例对象
CMS
执行类构造器<clinit>执行类的静态初始方法静态变量赋值生成class对象,放入堆中
GC器 连线代表可搭配使用
分代收集理论:1.大多数对象都是朝生暮死,在新生代就被回收了。这部分适合复制算法2.存活时间越长的对象被回收的概率越小,在老年代中的对象回收少,可以使用标记-整理 或者 标记-清除
💡如何理解翻译和编译?翻译是把字节码“逐条翻译”成机器码,再由CPU执行编译是把字节码“一次性编译”成机器码
CPU
给native方法准备的栈空间,hotspot中和虚拟机栈复用
•将字节码文件在方法区中生成类元信息•堆空间中生成类对象(class)•会选用类加载器:双亲委派机制•会生成运行时常量池,符号引用
Minor GC时来回交换
使用
单线程标记-整理算法简单高效可作为CMS的后备预案
应用类加载器AppClassLoader
字面量
多线程标记-清除算法低延迟会产生内存碎片过程:初始标记(STW),并发标记,重新标记(STW)和并发清除四个阶段
执行引擎
本地方法栈
数组长度
保存方法调用的引用地址(常量池中的method ref)
线程私有区
分区
虚拟机栈(Stack)
运行时数据区
young
抽象语法树
JVM内存模型
标记复制算法
单线程复制算法简单高效收集时暂停其他所有线程STW
新生代 占1/3
方法区
对象初始化过程
⚠️学习建议:只需要记住每个回收器属于哪个代?使用什么算法?有什么特点?适合什么场景?
垃圾回收 GC
java文件
标记清除算法
对齐填充
内存完整度:1.复制算法 2.标记整理算法 3.标记清理算法
•🧩每个方法执行都会创建一个 栈帧•生命周期与线程一致,线程结束,栈也随之销毁•不需要GC,因为随着方法执行完毕,栈帧自动出栈
为类的静态变量分配内存,并初始化默认值
栈帧1
优点:没有碎片,分配快(指针往后一移即可)缺点:1.内存利用率低,实际上只用了一半的内存2.对象活的久时效率会下降(所以才分代,适合新生代对象)
加载JVM的核心类库rt.jar
多线程分区式+标记-整理分为多个Region(逻辑堆分区)按垃圾多的优先来清理
方法返回地址
符号引用
锁消除当发现锁的变量是局部变量,就可以安全的优化掉锁。
•什么是符号引用?如类名 “java/lang/Object”,字段名 “name”;•什么是直接引用?如对象在内存中的地址;•这一步可能会触发其他类的加载。
当类加载器把 .class 文件加载进 JVM,并把方法和字段放入运行时数据区后,执行引擎就登场了,它会:•读取字节码指令•将其翻译为本地机器码•在 CPU 上运行
虚引用:通过PhantomReference创建出来的对象,GC可能随时回收它。用来跟踪垃圾回收的过程。
生成
销毁
方法信息
ParellelScavenge(并行)复制
引用计数法
类class信息
Eden GC后存活的对象
Parallel Old
Minor GC
JVM优化
线程私有
步骤:1.先标记所有存活对象2.将存活的对象都压缩到内存一端3.释放末尾的空间
类加载器在加载类时,会优先委托给父类加载器,只有当父类加载器无法加载该类时,子加载器才会尝试自己加载。好处:✅ 安全性防止用户自定义的类覆盖 Java 核心类。例如你写了个 java.lang.String,系统不会用你的版本。✅ 避免重复加载类一旦被加载,不需要再次加载,提升性能。❕什么场景要打破双亲委派
待更新~
扩展类加载器ExtClassLoader
Servivor1[占1/10] To
加载
复制算法
Eden
字节码 ↓解释器 ——→(执行) ↓(发现热点代码)JIT 编译器 ——→ 本地机器码 ——→(高效执行)
记录当前线程执行的字节码地址
可达性算法
全限定名
虚拟机栈
栈上分配如果对象不会逃逸到方法之外,JVM就可以将其分配到栈帧中,而不是堆中。这样做的好处是避免GC回收负担,减少堆内存分配,提高性能
异常处理表
存放class对象
弱引用:通过WeakReference创建出来的对象,当发生GC时就会被被回收。经常用于ThreadLocal的key,当threadLocal对象不再被使用时,可以及时回收
初始化
Serial 的多线程版本复制算法可配合CMS
准备
程序计数器
本地方法接口
类加载子系统
优点:没有碎片缺点:需要对象移动,开销比直接清除大(适合老年代,避免碎片)
引用级别:强引用->软引用->弱引用->虚引用
词法分析
ParellelScavenge
语义分析
1.经历过15次GC的对象(4bit位)2.大对象刚被创建就会放在老年代3.动态年龄判断:在S区相同年龄的对象占一半,>=该对象的会被放在老年代
运行时常量池
对象头
局部变量表
标记整理算法
serial Old
1.继承ClassLoader2.重写findClass()(推荐)或 loadClass()(破坏双亲委派)
用户自定义加载器
G1
💡热点代码怎么识别?JVM使用“计数器统计法”:方法调用超过一定次数,就被认定为热点;不仅限于方法,也包括热点循环比如:for (int i = 0; i < 100000; i++) { doSomething();}doSomething() 或整个循环都可能被 JIT 编译。
操作数栈
父类信息
多线程复制算法吞吐量优先不支持CS
标记-整理
对象存活判断算法
Major GC
验证
加载官方扩展包 /jre/lib/ext下的jar
serial(串行)复制
类加载器
栈帧2
GC
old
逐条将字节码翻译成机器码并执行,启动快但效率低
class字节码文件
解释器
线程共享区
G1(并发)全局整理+局部复制
双亲委派机制
ParNew(并行)复制
优点:简单缺点:造成大量内存碎片
启动类加载器BootStrapClassLoader
栈帧3
字节码生成器
老年代 占2/3
分代收集
我们写的应用程序中的类(即 classpath 路径下)
语法分析
Servivor0[占1/10] from
Serial Old(串行)标记-整理
内存利用率:1.标记整理算法 2.标记清除 3.复制算法
常量池符号引用替换为直接引用【因为多态】
ParNew
方法内联将被调用的方法代码直接插入到调用处,减少方法调用的栈帧开销,提高执行效率。
Parellel Old(并行)标记-整理
•文件格式验证:魔数、版本号;•语义验证:如指令是否非法,局部变量表下标是否越界;•类型验证:类是否继承自合法父类,方法重写是否正确;•字节码验证:操作码是否合法,栈深是否正确;•验证失败会抛 VerifyError。
从GC Root开始从上到下扫描,扫描不到的表示不可达。GC Root包括:1.栈中的引用2.方法区的静态变量3.方法区的常量引用4.本地方法栈中,native方法分配的对象⚠️不可达不是立即回收的第一次判断不可达,然后会判断对象有没有重写finalize()方法,有的话执行后再进行可达性分析,如果还是不可达才真正回收。
CMS(并发)标记-清除
注解抽象语法树
每个对象维护一个引用计数器,被一个变量引用时,计数+1,引用取消时,计数-1.直到计数为0时,表示可回收。❌ 弊端:无法处理循环引用,会导致内存泄漏
动态链接
class指针
方法执行完后,返回到上层的方法
多线程标记-整理算法吞吐量优先
serial
0 条评论
下一页