概述
JVM(Java Virtual Machine)是 Java 程序运行的虚拟机,负责将字节码翻译成机器码执行,提供跨平台能力和自动内存管理。
内存结构
运行时数据区
| 区域 | 线程共享 | 说明 |
|---|---|---|
| 堆(Heap) | 是 | 存放对象实例,GC 主要管理区域 |
| 方法区(Method Area) | 是 | 存放类信息、常量、静态变量 |
| 虚拟机栈(VM Stack) | 否 | 每个方法一个栈帧(局部变量表、操作数栈等) |
| 本地方法栈(Native Stack) | 否 | 为 Native 方法服务 |
| 程序计数器(PC Register) | 否 | 记录当前线程执行的字节码行号 |
JDK 8 内存模型变化
- 永久代(PermGen)→ 元空间(Metaspace)
- 元空间使用本地内存,不再受 JVM 堆大小限制
垃圾回收(GC)
如何判断对象可回收
- 引用计数法:循环引用问题
- 可达性分析:从 GC Roots 出发,不可达的对象可回收
GC Roots 包括
- 虚拟机栈中引用的对象
- 方法区中类静态属性引用的对象
- 方法区中常量引用的对象
- 本地方法栈中 JNI 引用的对象
垃圾回收算法
- 标记-清除:产生碎片
- 标记-整理:移动对象,无碎片但开销大
- 复制算法:两块区域来回复制,适合新生代
- 分代收集:新生代用复制,老年代用标记-整理
常见垃圾回收器
| 回收器 | 算法 | 适用区域 | 特点 | |——–|——|———-|——| | Serial | 复制 | 新生代 | 单线程,Client 模式默认 | | ParNew | 复制 | 新生代 | Serial 多线程版 | | Parallel Scavenge | 复制 | 新生代 | 吞吐量优先 | | CMS | 标记-清除 | 老年代 | 低延迟,有碎片问题 | | G1 | 分区收集 | 全堆 | JDK 9 默认,可预测停顿 | | ZGC | 着色指针 | 全堆 | 超低延迟(<10ms) |
类加载机制
类加载过程
- 加载:读取 class 文件,生成 Class 对象
- 验证:校验字节码格式和安全性
- 准备:为静态变量分配内存并赋默认值
- 解析:将常量池符号引用替换为直接引用
- 初始化:执行
<clinit>()方法
双亲委派模型
- 自底向上检查是否已加载,自顶向下尝试加载
- Bootstrap → Extension → Application ClassLoader
- 可自定义 ClassLoader 打破双亲委派
JVM 调优常用参数
# 堆大小
-Xms512m -Xmx2g
# 新生代大小
-Xmn256m
# 元空间大小
-XX:MetaspaceSize=256m -XX:MaxMetaspaceSize=512m
# GC 日志
-Xlog:gc*:file=gc.log
# 使用 G1 收集器
-XX:+UseG1GC
常见面试题
- JVM 内存模型是怎样的?
- 什么是双亲委派模型?为什么需要?
- CMS 和 G1 的区别?
- 什么情况下会发生 OOM?如何排查?
- JVM 调优的常见手段?
参考资料
- 《深入理解 Java 虚拟机》- 周志明