☕ JVM 核心知识
I. 内存模型 (Runtime Data Areas)
1. 区域划分
JVM 在执行 Java 程序的过程中会把它所管理的内存划分为若干个不同的数据区域:
线程私有:
- 程序计数器 (Program Counter Register):当前线程所执行的字节码的行号指示器,是唯一一个不会出现 OOM 的区域.
- 虚拟机栈 (VM Stack):描述 Java 方法执行的内存模型,每个方法执行时都会创建一个栈帧用于存储局部变量表、操作数栈、动态链接、方法出口等信息.
- 本地方法栈 (Native Method Stack):与虚拟机栈类似,不过是为 Native 方法服务.
线程共享:
- 堆 (Heap):JVM 管理的最大一块内存,存放对象实例,是 GC 的主要区域.
- 方法区 (Method Area):存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据 (JDK 8 后由元空间 Metaspace 实现,使用本地内存).
2. 堆内存分布
- 新生代 (Young Generation):
- Eden 区:新对象主要分配在 Eden 区.
- Survivor 区 (S0, S1):存活对象在 S0/S1 之间复制,默认比例 Eden:S0:S1 = 8:1:1.
- 老年代 (Old Generation):存放生命周期较长的对象.
II. 垃圾回收 (GC)
1. 如何判断对象已死?
- 引用计数法:对象被引用一次加1,引用失效减1。无法解决循环引用问题.
- 可达性分析算法 (主流):从 GC Roots (如栈中引用的对象、静态变量引用的对象) 出发,通过引用链向下搜索,不可达的对象即可回收.
2. 常见的 GC 算法
- 标记-清除 (Mark-Sweep):标记出所有需要回收的对象,统一回收。缺点:内存碎片.
- 标记-复制 (Mark-Copy):将内存分为两块,每次只用一块,将存活对象复制到另一块。优点:无碎片;缺点:内存利用率低 (用于新生代).
- 标记-整理 (Mark-Compact):标记存活对象,将其向一端移动,清理掉边界以外的内存。优点:无碎片 (用于老年代).
3. 说明一下 CMS 和 G1
CMS (Concurrent Mark Sweep):
- 以获取最短回收停顿时间为目标.
- 基于“标记-清除”算法.
- 过程:初始标记(STW) -> 并发标记 -> 重新标记(STW) -> 并发清除.
- 缺点:对 CPU 敏感、产生内存碎片.
G1 (Garbage First):
- 面向服务端应用,可预测停顿.
- 将堆划分为多个大小相等的 Region.
- 整体看是“标记-整理”,局部看是“标记-复制”,不会产生内存碎片.
- 适合大内存机器,JDK 9 默认收集器.
III. 类加载机制
1. 类加载过程
- 加载 (Loading):通过全类名获取二进制字节流,将静态存储结构转化为方法区的运行时数据结构.
- 链接 (Linking):
- 验证:确保字节码符合规范.
- 准备:为静态变量分配内存并设置零值.
- 解析:将常量池内的符号引用替换为直接引用.
- 初始化 (Initialization):执行类构造器
<clinit>方法 (静态代码块赋值).
2. 双亲委派模型 (Dual Parent Delegation)
- 定义:当一个类加载器收到类加载请求时,首先委托给父类加载器去完成,父加载器无法加载时才自己尝试加载.
- 好处:保证核心类库 (如
java.lang.Object) 的安全性,避免用户自定义类覆盖核心类. - 打破场景:JDBC (通过 SPI 机制)、Tomcat (Web 应用隔离).
IV. 常见 JVM 参数与排查
1. 常用参数
-Xms/-Xmx:设置堆的初始大小和最大大小 (通常设置为相同,避免动态扩容抖动).-Xmn:设置新生代大小.-XX:MetaspaceSize:设置元空间初始大小.-XX:+PrintGCDetails:打印 GC 详细日志.-XX:+HeapDumpOnOutOfMemoryError:OOM 时自动 Dump 堆内存.
2. 线上排查工具
jps:查看 Java 进程状态.jstat:监视虚拟机各种运行状态信息 (GC 情况等).jinfo:实时查看和调整虚拟机各项参数.jmap:生成堆转储快照 (dump 文件).jstack:生成虚拟机当前时刻的线程快照 (排查死锁、CPU 飙高).- Arthas:阿里开源的 Java 诊断工具 (推荐).