JVM 面试题
1. JVM 内存模型是怎样的?
JVM 运行时数据区分为:
线程私有:
- 程序计数器:记录当前线程执行的字节码行号
- 虚拟机栈:方法调用时创建栈帧,存放局部变量表、操作数栈等
- 本地方法栈:Native 方法调用
线程共享:
- 堆:存放对象实例,GC 主要管理区域
- 方法区(元空间):存放类信息、常量、静态变量
2. 堆内存的分代结构?
堆
├── 新生代(1/3)
│ ├── Eden 区(8/10)
│ ├── Survivor 0(1/10)
│ └── Survivor 1(1/10)
└── 老年代(2/3)- 对象优先在 Eden 分配
- 经历 Minor GC 后存活的对象进入 Survivor
- 每经历一次 GC 年龄 +1,达到 15(默认)进入老年代
- 大对象直接进入老年代
3. 类加载过程是怎样的?
加载 → 验证 → 准备 → 解析 → 初始化- 加载:获取类的二进制字节流,转为方法区数据结构,生成 Class 对象
- 验证:确保 Class 文件格式正确
- 准备:为静态变量分配内存并赋默认值
- 解析:将常量池中的符号引用替换为直接引用
- 初始化:执行类构造器
<clinit>方法
4. 什么是双亲委派模型?为什么要这样设计?
双亲委派:类加载器收到加载请求时,先委托父加载器加载,父加载器找不到时才自己加载。
好处:
- 避免类的重复加载
- 保证核心 API 不被篡改(如 String 类只能由 Bootstrap ClassLoader 加载)
5. 垃圾回收算法有哪些?
| 算法 | 原理 | 优缺点 |
|---|---|---|
| 标记-清除 | 标记可回收对象,然后清除 | 产生内存碎片 |
| 标记-整理 | 标记后让存活对象向一端移动 | 无碎片,耗时长 |
| 复制 | 分两块内存,存活对象复制到另一块 | 无碎片,内存利用率低 |
| 分代收集 | 新生代用复制,老年代用标记-整理 | 综合性能最优 |
6. 如何排查 OOM 问题?
- 获取 dump 文件:
-XX:+HeapDumpOnOutOfMemoryError - 使用 MAT / JProfiler 分析 dump 文件
- 查看大对象和 GC Roots 引用链
- 定位到具体代码位置进行优化