JVM
JVM
JVM 面试八股文
1. JVM 内存结构
JVM 运行时数据区域 | 区域 | 作用 | GC 影响 | |---|---|---| | 程序计数器 | 记录当前线程执行的字节码指令地址,线程私有 | 不会发生 OOM | | 虚拟机栈 | 方法执行时存储局部变量、操作数栈、动态链接等 | 栈溢出 (
StackOverflowError) | | 本地方法栈 | 存放native方法的调用栈信息 | 可能导致 OOM | | 堆 | 存放对象实例,垃圾回收主要区域 | 受 GC 影响 (OutOfMemoryError) | | 方法区(元空间) | 存储类信息、常量、静态变量、JIT 编译代码 | JDK8 及以上使用 元空间 |堆内存划分
新生代(Young):Eden(8)+ S0(1)+ S1(1),使用 标记-复制算法。
老年代(Old):存放存活时间长的对象,使用 标记-整理算法。
字符串常量池
JDK7 及以前:位于方法区(永久代)。
JDK8 及以后:位于堆内存,回收更高效。
2. JVM 对象创建 & 访问方式
- 对象创建过程
- 类加载检查:先检查类是否已经加载(类信息存储在方法区)。
- 分配内存:
- 指针碰撞(无内存碎片)。
- 空闲列表(有内存碎片)。
- 内存分配安全性:
- CAS + 重试
- TLAB(Thread Local Allocation Buffer):线程独享的小块堆内存。
- 初始化零值。
- 设置对象头(哈希码、GC 分代年龄、锁信息等)。
- 调用构造方法
init()。
- 对象访问方式 | 方式 | 特点 | 优缺点 | |---|---|---| | 句柄池 | 通过句柄找到对象地址 | 间接访问,修改对象地址时只需维护句柄池 | | 直接指针 | 直接存储对象地址 | 访问速度更快(HotSpot 采用) |
3. JVM 垃圾回收(GC)
四种引用类型 | 引用类型 | GC 影响 | 用途 | |---|---|---| | 强引用 | 不会被回收 | 普通对象引用 | | 软引用 | 内存不足时回收 | 缓存 | | 弱引用 | GC 时回收 |
ThreadLocal| | 虚引用 | 仅用于监听对象回收 | 管理直接内存 |对象可达性判断
引用计数法(已淘汰):无法解决循环引用问题。
可达性分析算法(GC Roots):
栈帧局部变量
静态变量
类加载器
- JVM GC 采用此方法
GC 算法 | GC 算法 | 特点 | 优缺点 | |---|---|---| | 标记-清除 | 标记存活对象,清除未标记对象 | 容易产生内存碎片 | | 标记-复制 | 将存活对象复制到另一块区域 | 浪费一半空间 | | 标记-整理 | 清理碎片,整理成连续空间 | 适用于老年代 | | 分代回收 | 新生代(标记-复制)+ 老年代(标记-整理) | 优化垃圾回收效率 |
垃圾回收器 | GC | 作用 | 特点 | |---|---|---| | Serial GC | 单线程,新生代(标记-复制) | Stop The World(STW) | | Parallel GC | 多线程,吞吐量优先 | JDK8 默认 GC | | CMS GC | 老年代,并发标记清除 | 低延迟,但有碎片 | | G1 GC | JDK9 默认 GC,分区回收 | 低延迟 + 高吞吐 |
STW(Stop The World)
GC 时暂停所有用户线程,确保 GC 过程一致性。
G1 降低 STW 影响,通过增量式 GC 进行优化。
4. JVM 类加载机制
类加载过程 | 阶段 | 作用 | |---|---| | 加载 | 读取
.class文件,转换为Class对象 | | 连接 | 验证(校验字节码)、准备(分配静态变量内存)、解析(符号引用转为直接引用) | | 初始化 | 执行静态代码块clinit()|双亲委派模型
加载顺序:
Bootstrap(rt.jar) →ExtClassLoader(ext 目录) →AppClassLoader(classpath)作用:防止 核心 API 被篡改(如
String类)。自定义类加载器:
不破坏双亲委派:继承
ClassLoader,重写findClass()。打破双亲委派:重写
loadClass()。Tomcat 类加载机制
每个 Web 应用有独立的类加载器,避免类冲突。
打破双亲委派,优先加载 Web 应用中的类。
5. JVM 调优
JVM 参数 | 参数 | 作用 | 示例 | |---|---|---| |
-Xms| 初始堆大小 |-Xms2G| |-Xmx| 最大堆大小 |-Xmx5G| |-Xss| 每个线程栈大小 |-Xss256k| |-XX:NewRatio| 新生代与老年代比例 |-XX:NewRatio=2| |-XX:MetaspaceSize| 元空间初始大小 |-XX:MetaspaceSize=256m|GC 监控工具 | 工具 | 作用 | |---|---| |
jstack| 查看线程堆栈 | |jmap| 查看堆内存分布 | |jconsole| 图形化查看 GC | | Arthas | 阿里开源 JVM 诊断神器 |GC 调优策略
- 避免创建过多对象(减少 GC 频率)。
- 调整 GC 线程数(
-XX:ParallelGCThreads)。 - 使用
intern()进行字符串池优化。 - 减少 Full GC 触发频率(避免
System.gc())。
6. 其他 JVM 相关知识
Java 为什么能跨平台?
JVM 是与平台相关的,不同平台的 JVM 翻译
.class文件,确保一次编译,处处运行。JIT(即时编译器)优化 | 优化方式 | 作用 | |---|---| | 缓存 | 热点代码缓存,提高执行效率 | | 逃逸分析 | 对象未逃出方法,直接在栈上分配 | | 锁消除 | 移除不必要的锁,减少同步开销 |
如何判断两个类是否相同?
类加载器不同,则类不同。
总结
- JVM 运行时数据区 & 内存分配机制。
- GC 机制 & JVM 调优策略。
- 类加载过程 & 双亲委派模型。
- JIT 编译优化 & 逃逸分析。
- GC 监控工具 & 调优方法。