JVM
核心
- 类加载子系统
- 运行时数据区
- 字节码执行引擎
类加载子系统
类加载器
- Bootstrap类加载器
- Ext类加载器
- App类加载器
- 自定义类加载器
- 继承ClassLoader、覆写 findClass() 方法
双亲委派模型(Parent Delegation Model)是 Java 类加载器使用的一种机制,用于确保 Java 程序的稳定性和安全性。在这个模型中,类加载器在尝试加载一个类时,首先会委派给其父加载器去尝试加载这个类,只有在父加载器无法加载该类时,子加载器才会尝试自己去加载。
Tomcat打破了双亲委派。
- 为什么?
- 怎么实现的?
额外话题:热加载/热更新/加密程序
Class文件
结构
解析
javap
jclasslib
字节码指令见官方文档《The Java® Virtual Machine Specification Java SE 8 Edition》
运行时数据区
根据 Java 虚拟机规范的规定,运行时数据区可以分为以下几个部分:
- 程序计数器(Program Counter Register)
- Java 虚拟机栈(Java Virtual Machine Stacks)
- 本地方法栈(Native Method Stack)
- 堆(Heap)
- 方法区(Method Area)元空间(MetaSpace)
栈桢
字节码执行引擎
垃圾回收
垃圾回收(Garbage Collection,GC),顾名思义就是释放垃圾占用的空间,防止内存爆掉。有效的使用可以使用的内存,对内存堆中已经死亡的或者长时间没有使用的对象进行清除和回收。
1960 年,基于 MIT 的 Lisp 首先提出了垃圾回收的概念。
垃圾判断算法
- 引用计数算法
- 可达性分析算法
引用计数算法
引用计数算法(Reachability Counting)是通过在对象头中分配一个空间来保存该对象被引用的次数(Reference Count)。
如果该对象被其它对象引用,则它的引用计数加 1,如果删除对该对象的引用,那么它的引用计数就减 1,当该对象的引用计数为 0 时,那么该对象就会被回收。
引用计数算法无法解决循环依赖的问题。
可达性分析算法
可达性分析算法(Reachability Analysis)的基本思路是,通过 GC Roots 作为起点,然后向下搜索,搜索走过的路径被称为 Reference Chain(引用链),当一个对象到 GC Roots 之间没有任何引用相连时,即从 GC Roots 到该对象节点不可达,则证明该对象是需要垃圾收集的。
所谓的 GC Roots,就是一组必须活跃的引用,不是对象,它们是程序运行时的起点,是一切引用链的源头。在 Java 中,GC Roots 包括以下几种:
- 虚拟机栈中的引用(方法的参数、局部变量等)
- 本地方法栈中 JNI 的引用
- 类静态变量
- 运行时常量池中的常量(String 或 Class 类型)
垃圾收集算法
- 标记清除算法(Mark-Sweep)
- 复制算法(Copying)
- 标记整理算法(Mark-Compact)
- 分代收集算法(Generational Collection)
- 分区收集算法(Regional Collection)
垃圾收集器
JVM 的垃圾收集器主要分为两大类:分代收集器和分区收集器,分代收集器的代表是 CMS,分区收集器的代表是 G1 和 ZGC。
分代的垃圾回收问题
- 老年代使用了年轻代对象怎么办?使用card-table
CMS(Concurrent Mark Sweep)
“最短停顿时间”指的是垃圾回收过程中,应用程序暂停的时间尽可能短。也就是在垃圾回收时,Stop The World(STW,全局停顿)时间要尽量短,因为只有 STW 够短,那么应用程序才能更快的执行。
- 是什么
- 目标是什么
- 运行原理是什么
- 优点是什么
- 并发收集、低停顿
- 缺点是什么
- 对 CPU 资源非常敏感,因此在 CPU 资源紧张的情况下,CMS 的性能会大打折扣。
- CMS 采用的是「标记-清除」算法,会产生大量的内存碎片,导致空间不连续,当出现大对象无法找到连续的内存空间时,就会触发一次 Full GC,这会导致系统的停顿时间变长。
- CMS 无法处理浮动垃圾,当 CMS 在进行垃圾回收的时候,应用程序还在不断地产生垃圾,这些垃圾会在 CMS 垃圾回收结束之后产生,这些垃圾就是浮动垃圾,CMS 无法处理这些浮动垃圾,只能在下一次 GC 时清理掉。
- 有什么需要注意的问题
- G1和CMS的三色标记法及漏标问题
以获取最短回收停顿时间为目标,采用“标记-清除”算法,分 4 大步进行垃圾收集,其中初始标记和重新标记会 STW,JDK 1.5 时引入,JDK9 被标记弃用,JDK14 被移除,详情可见JEP 363: Remove the Concurrent Mark Sweep (CMS) Garbage Collector。
四个步骤:
- 初始标记
- 并发标记
- 重新标记
- 并发清除
官方文档:Concurrent Mark Sweep (CMS) Collector
G1(Garbage-First Garbage Collector)
- 是什么
- G1 有五个属性:分代/分区、增量、并行、标记整理、STW。
- 目标是什么
- 运行原理是什么
- 特点是什么
- 并不是回收全部垃圾,而是尽可能在用户规定得停顿时间内尽可能回收垃圾多的region。
- 优点是什么
- 缺点是什么
- 有什么需要注意的问题
- G1和CMS的三色标记法及漏标问题
- 老年代指向年轻代的引用怎么办?记忆集rset(remember set),G1对每个region维护了一个rset,记忆集中维护了指向自己的region的指针,并且标记指针分别在那些卡页的范围之内。由于G1使用了很多的region(每个region都有一个rset),所以G1使用了较高的内存,基本占用Java对内存的10%~20%的额外内存来维持收集器的工作。
- 会产生浮动垃圾
工作流程:
- 1.初始标记
- 仅仅标记GC roots能直接关联到的对象。该步骤需要STW,但是时间极短。
- 2.并发标记
- 从GC roots使用可达性算法,对堆内存中对象进行标记(三色标记法),递归扫描整个堆。该步骤耗时过长,是与用户业务程序并发执行。
- 3.重新标记
- 对用户线程短暂的STW,用于处理并发标记中对象的一些变更情况的最终确定。
- 4.筛选回收
- G1会根据用户规定的停顿时间,最大的回收region,将需要被回收的region复制到空白region中,再将原region全部回收。该步骤也需要STW,因为涉及到了对象的移动(一个region到另一个region)。
三色标记法
黑色:自身及其子对象已经被标记。
灰色:自身已经被标记,但是子对象没有完全被标记
白色:自身未被标记,如果标记结束后仍然为白色,则是垃圾对象。
三色标记法为什么存在漏标问题?
在并发标记阶段会出现漏标问题, 由于是GC线程和用户线程同时运行的。
并发标记前:A和B两个对象,B引用C。
并发标记后:A和B两个对象,A引用C,B不引用C了。
此时从B的角度看,C是垃圾。但是A看,C不是垃圾。
官方文档:Garbage-First Garbage Collector
g1论文:g1-paper-ismm.dvi
ZGC(The Z Garbage Collector)
- 是什么
- 目标是什么
- 停顿时间不超过 10ms;
- 停顿时间不会随着堆的大小,或者活跃对象的大小而增加;
- 支持 8MB~4TB 级别的堆,未来支持 16TB。
- 运行原理是什么
- 优点是什么
- 缺点是什么
- 有什么需要注意的问题
- G1和CMS的三色标记法及漏标问题
最后编辑:张三 更新时间:2025-10-28 19:01