|
| 1 | +--- |
| 2 | +title: JVM核心知识点八股文 |
| 3 | +date: 2025-12-11 15:30:00 |
| 4 | +categories: |
| 5 | + - 后端面试 |
| 6 | +tags: |
| 7 | + - JVM |
| 8 | + - 垃圾回收 |
| 9 | + - 内存模型 |
| 10 | + - 八股文 |
| 11 | +permalink: /jvm-interview-2025/ |
| 12 | +--- |
| 13 | + |
| 14 | +# JVM 核心知识点八股文(高频面试版) |
| 15 | +本文整理 JVM 面试中最常考察的核心知识点,覆盖内存结构、垃圾回收、类加载、性能调优等高频考点,适合面试复习和知识点梳理。 |
| 16 | + |
| 17 | +## 一、JVM 内存结构(运行时数据区) |
| 18 | +JDK 8 及以上版本的内存结构移除了永久代(PermGen),替换为元空间(Metaspace),核心分为以下区域: |
| 19 | + |
| 20 | +### 1. 线程私有区域 |
| 21 | +- **程序计数器**:记录当前线程执行的字节码行号,唯一不会抛出 OOM 的区域; |
| 22 | +- **虚拟机栈**:存储方法调用的栈帧(局部变量表、操作数栈、动态链接、方法出口),栈深度溢出抛 `StackOverflowError`,内存不足抛 OOM; |
| 23 | +- **本地方法栈**:为 Native 方法服务,与虚拟机栈逻辑一致,同样会抛 `StackOverflowError`/OOM。 |
| 24 | + |
| 25 | +### 2. 线程共享区域 |
| 26 | +- **堆**:JVM 最大的内存区域,存储对象实例和数组,是垃圾回收(GC)的核心区域; |
| 27 | + - 分代:新生代(Eden + Survivor0 + Survivor1,比例 8:1:1)、老年代; |
| 28 | + - 溢出:对象无法分配内存时抛 `OutOfMemoryError: Java heap space`。 |
| 29 | +- **元空间(Metaspace)**:替代永久代,存储类元信息、常量池、方法字节码等,直接使用本地内存,默认无上限(可通过 `-XX:MetaspaceSize`/`-XX:MaxMetaspaceSize` 限制),溢出抛 `OutOfMemoryError: Metaspace`。 |
| 30 | + |
| 31 | +### 3. 直接内存(非运行时数据区) |
| 32 | +- 基于 NIO 的堆外内存,不受 JVM 堆大小限制,但受物理内存限制,溢出抛 `OutOfMemoryError: Direct buffer memory`。 |
| 33 | + |
| 34 | +## 二、垃圾回收(GC)核心 |
| 35 | +### 1. 如何判断对象可回收? |
| 36 | +- **引用计数法**:对象引用数为 0 则标记为可回收,缺点:无法解决循环引用问题; |
| 37 | +- **可达性分析算法**:以 GC Roots 为起点,遍历对象引用链,无引用链的对象标记为可回收; |
| 38 | + - GC Roots 包括:虚拟机栈中引用的对象、本地方法栈中引用的对象、方法区中类静态属性/常量引用的对象。 |
| 39 | + |
| 40 | +### 2. 常见 GC 算法 |
| 41 | +- **标记-清除(Mark-Sweep)**:标记可回收对象 → 清除,缺点:内存碎片、效率低; |
| 42 | +- **标记-复制(Mark-Copy)**:将内存分为两块,只使用一块,回收时将存活对象复制到另一块,优点:无内存碎片,缺点:内存利用率低(仅 50%),新生代(Eden/Survivor)采用此算法; |
| 43 | +- **标记-整理(Mark-Compact)**:标记可回收对象 → 存活对象向一端移动 → 清除端外内存,无碎片、利用率 100%,老年代采用此算法。 |
| 44 | + |
| 45 | +### 3. 经典垃圾收集器 |
| 46 | +| 收集器 | 适用区域 | 核心特点 | 回收线程 | |
| 47 | +|--------------|----------|------------------------------|----------| |
| 48 | +| Serial | 新生代 | 单线程、STW 时间长、简单高效 | 单线程 | |
| 49 | +| ParNew | 新生代 | Serial 多线程版本 | 多线程 | |
| 50 | +| Parallel Scavenge | 新生代 | 关注吞吐量(运行代码时间/总时间) | 多线程 | |
| 51 | +| Serial Old | 老年代 | Serial 老年代版本 | 单线程 | |
| 52 | +| Parallel Old | 老年代 | Parallel Scavenge 老年代版本 | 多线程 | |
| 53 | +| CMS | 老年代 | 低延迟、并发回收、三步 STW | 多线程 | |
| 54 | +| G1 | 整堆 | 分区回收、兼顾吞吐量和延迟 | 多线程 | |
| 55 | +| ZGC/Shenandoah | 整堆 | 超低延迟(毫秒级)、大内存友好 | 多线程 | |
| 56 | + |
| 57 | +### 4. GC 触发时机 |
| 58 | +- **Minor GC(新生代 GC)**:Eden 区满时触发,频率高、STW 时间短; |
| 59 | +- **Major GC(老年代 GC)**:老年代空间不足时触发,常伴随 Minor GC,STW 时间长; |
| 60 | +- **Full GC**:整堆回收(新生代+老年代+元空间),触发场景:老年代满、元空间满、System.gc() 显式调用、Minor GC 后老年代无法容纳晋升对象。 |
| 61 | + |
| 62 | +## 三、类加载机制 |
| 63 | +### 1. 类加载的完整流程 |
| 64 | +- **加载**:将类的字节码文件(.class)加载到内存,生成 Class 对象; |
| 65 | +- **验证**:校验字节码合法性(文件格式、元数据、字节码指令、符号引用验证); |
| 66 | +- **准备**:为类静态变量分配内存并赋默认值(如 int → 0,引用 → null); |
| 67 | +- **解析**:将符号引用替换为直接引用(内存地址); |
| 68 | +- **初始化**:执行静态代码块、为静态变量赋初始值(程序员定义的值)。 |
| 69 | + |
| 70 | +### 2. 类加载器分类 |
| 71 | +- **启动类加载器(Bootstrap ClassLoader)**:C++ 实现,加载 JRE/lib 核心类(如 rt.jar); |
| 72 | +- **扩展类加载器(Extension ClassLoader)**:Java 实现,加载 JRE/lib/ext 扩展类; |
| 73 | +- **应用类加载器(Application ClassLoader)**:Java 实现,加载用户自定义类(classpath 下); |
| 74 | +- **自定义类加载器**:继承 ClassLoader,实现自定义加载逻辑(如热部署、加密类加载)。 |
| 75 | + |
| 76 | +### 3. 双亲委派机制 |
| 77 | +- **核心规则**:类加载时先委托父加载器加载,父加载器无法加载时再自己加载; |
| 78 | +- **优点**:避免类重复加载、保证核心类(如 java.lang.String)不被篡改; |
| 79 | +- **打破场景**:Tomcat 类加载(为不同 Web 应用隔离类)、热部署、SPI 加载(如 JDBC)。 |
| 80 | + |
| 81 | +## 四、JVM 性能调优 |
| 82 | +### 1. 核心调优参数 |
| 83 | +```bash |
| 84 | +# 堆内存设置 |
| 85 | +-Xms2g # 初始堆内存(建议与-Xmx一致,避免频繁扩容) |
| 86 | +-Xmx2g # 最大堆内存 |
| 87 | +-Xmn512m # 新生代内存(建议占堆的 1/4~1/3) |
| 88 | +-XX:SurvivorRatio=8 # Eden:S0:S1 = 8:1:1 |
| 89 | +-XX:NewRatio=2 # 老年代:新生代 = 2:1(JDK8 前) |
| 90 | + |
| 91 | +# 元空间设置 |
| 92 | +-XX:MetaspaceSize=128m # 元空间初始大小 |
| 93 | +-XX:MaxMetaspaceSize=256m # 元空间最大大小 |
| 94 | + |
| 95 | +# GC 收集器设置 |
| 96 | +-XX:+UseParallelGC # 新生代使用 Parallel Scavenge |
| 97 | +-XX:+UseParallelOldGC # 老年代使用 Parallel Old |
| 98 | +-XX:+UseG1GC # 使用 G1 收集器 |
| 99 | +-XX:MaxGCPauseMillis=200 # G1 最大停顿时间 |
| 100 | + |
| 101 | +# 日志配置 |
| 102 | +-XX:+PrintGCDetails # 打印 GC 详细日志 |
| 103 | +-XX:+PrintGCTimeStamps # 打印 GC 时间戳 |
| 104 | +-Xloggc:/tmp/gc.log # GC 日志输出路径 |
0 commit comments