1、什么是 JVM
答案
JVM 是 Java 虚拟机,是运行 Java 字节码的虚拟机器。作用:
- 把
.class字节码翻译成机器指令执行 - 实现 一次编写,到处运行 跨平台
- 负责 内存管理、垃圾回收、类加载、即时编译、安全校验
2、JVM 运行时数据区 5 大内存区域(必背)
答案
- 程序计数器:记录当前线程执行字节码行号,唯一没有 OOM的区域。
- 虚拟机栈(Java 栈) :方法执行、局部变量、栈帧,线程私有。
- 本地方法栈:给 Native 方法服务,JNI 调用。
- 堆 Heap:所有对象实例、数组,GC 主要回收区域,线程共享。
- 方法区:存放类结构、常量、静态变量、运行时常量池、元数据。
3、程序计数器作用
答案
记录线程当前执行到第几行字节码;
线程切换后恢复执行位置;
是 JVM 唯一不会内存溢出的内存区域。
4、虚拟机栈 栈帧是什么
答案
每调用一个方法就创建一个栈帧,方法结束栈帧出栈。栈帧包含:
- 局部变量表
- 操作数栈
- 动态链接
- 方法返回地址
5、堆内存结构划分(新生代 / 老年代)
答案堆分两大块:
-
新生代 Young
- Eden 伊甸区
- Survivor From
- Survivor To
-
老年代 Old
默认比例:Eden : From : To = 8:1:1
6、对象创建流程
答案
- 类加载检查
- 分配内存(指针碰撞 / 空闲列表)
- 初始化默认值
- 设置对象头
- 执行构造方法
- 返回对象引用
7、GC 垃圾回收 哪些对象可回收
答案
- 没有任何强引用指向的对象
- 引用计数为 0
- 可达性分析中不在 GC Root 引用链上
8、GC Root 有哪些? 为什么要 GC Root?
答案
GC Root 是垃圾回收的起始引用点,从 Root 往下遍历,找不到的对象就是垃圾。
常见GC Root:
- 虚拟机栈中引用的对象
- 本地方法栈 JNI 引用对象
- 方法区静态变量引用
- 常量池引用
- 活跃线程持有的对象
9、四种引用类型(强 / 软 / 弱 / 虚)
答案
- 强引用:正常 new,GC 永不回收
- 软引用 SoftReference:内存不足才回收,适合缓存
- 弱引用 WeakReference:下次 GC 必回收,适合 LeakCanary、生命周期监听
- 虚引用 PhantomReference:仅做回收通知,不能拿对象
10、Minor GC、Major GC、Full GC 区别
答案
- Minor GC:只回收新生代,频率高、速度快
- Major GC:只回收老年代
- Full GC:整堆回收(新生代 + 老年代 + 方法区),耗时高、尽量避免
11、垃圾回收算法 4 种
答案
- 标记清除:先标记再清除,产生内存碎片
- 复制算法:新生代用,分成两块,存活复制到另一块,无碎片
- 标记整理算法:老年代用,标记后向一端压缩整理,无碎片
- 分代收集:新生代复制、老年代标记整理
12、常见垃圾收集器
答案
- Serial:单线程收集器
- Parallel:多线程吞吐量优先
- CMS:并发低停顿,老年代
- G1:分区收集,可预测停顿
- ZGC、Shenandoah:超低延迟大堆收集器
13、CMS 垃圾回收流程
答案
- 初始标记
- 并发标记
- 重新标记
- 并发清除
特点:并发回收、低停顿,有浮动垃圾、内存碎片。
14、JVM 内存溢出 OOM 常见场景
答案
- 堆内存溢出:对象过多、大集合不释放
- 虚拟机栈溢出:递归死循环
- 方法区溢出:动态生成大量类
- 直接内存溢出:NIO 未释放缓冲区
15、调用 System.gc() 会立即垃圾回收吗?
不会立即执行,只是「建议」JVM 回收,不保证马上 GC,也不保证一定回收。
调用
System.gc()只是向 JVM 建议垃圾回收,不会立即执行、也不保证一定执行,JVM 会在合适的安全点自行决定何时 GC,开发者不能强制立即回收。
16、可达性分析原理是什么?
答案
JVM 不用引用计数,用可达性分析:
以 GC Root 为起点向下遍历引用链,能遍历到的是存活对象,遍历不到的判定为垃圾,可被回收。
优点:解决循环引用无法回收的问题。
17、引用计数为什么不用了?
答案
引用计数靠对象被引用次数,为 0 就回收;
致命缺点:两个对象互相循环引用,计数永远不为 0,永远回收不了,造成内存泄漏,所以 JVM 主流用可达性分析。
18、新生代为什么是 8:1:1 比例?
答案
Eden:S0:S1 = 8:1:1
大部分对象朝生夕死,大多在 Eden 诞生、一次 Minor GC 就死了;
两个 Survivor 来回复制存活对象,节省内存、减少空间浪费。
19、什么是对象晋升到老年代?条件有哪些
答案
新生代对象满足任意条件进入老年代:
- 对象年龄达到15 岁(默认)
- Survivor 放不下存活对象,直接晋升
- 大对象直接分配到老年代(避免新生代复制开销)
20、Minor GC 触发条件?
答案
Eden 区满了就触发 Minor GC;
清理新生代,把存活对象复制到 Survivor,年龄达标升入老年代。
21、Full GC 触发条件有哪些?
答案
- 老年代空间不足
- 方法区 / 元空间不足
- 显式调用
System.gc() - Minor GC 后晋升老年代放不下
- CMS 并发失败、空间溢出
Full GC 开销极大,项目要尽量避免。
22、JVM 栈溢出和堆溢出区别
答案
- 栈溢出 StackOverflowError:递归太深、方法嵌套过多,虚拟机栈帧过多
- 堆溢出 OOM:创建对象太多、大集合不释放、静态常驻对象,堆内存占满
一、基础概念
- JVM 作用一次编译到处运行,负责类加载、内存管理、垃圾回收、字节码执行。
- JVM 运行时数据区 5 块程序计数器、虚拟机栈、本地方法栈、堆、方法区。
- 程序计数器记录字节码执行行号,线程私有,唯一不会 OOM。
- 虚拟机栈方法执行栈帧,线程私有,递归太深会栈溢出。
- 堆存放所有对象和数组,线程共享,GC 主要回收区域。
- 方法区存类元数据、静态变量、常量,JDK8 由永久代改成元空间。
二、类加载
- 类加载过程加载、验证、准备、解析、初始化、使用、卸载。
- 双亲委派子加载器先委托父加载器,父加载不了自己再加载;安全防篡改、避免重复加载。
- 能不能破坏双亲委派能,自定义类加载器不委托父加载器即可,Tomcat 就是典型。
三、GC 垃圾回收
- GC 怎么判断垃圾采用可达性分析,从 GC Root 遍历,找不到引用链就是垃圾。
- GC Root 有哪些栈引用、JNI 引用、静态变量、常量、活跃线程、锁对象。
- 为什么不用引用计数解决不了循环引用,没法回收。
- 四种引用强引用永不回收;软引用内存不足回收;弱引用下次 GC 必回收;虚引用只做回收通知。
- 新生代比例 8:1:1对象朝生夕死,两块 Survivor 来回复制,节省内存减少浪费。
- 对象什么时候进老年代年龄到 15、Survivor 放不下、大对象直接进老年代。
- Minor GCEden 满触发,只回收新生代,速度快。
- Full GC 触发时机老年代满、元空间不足、Minor GC 晋升失败、手动调用 System.gc ()。
- System.gc()只是建议 JVM 回收,不会立即执行,也不保证一定回收。
- STW 是什么GC 暂停所有业务线程,只跑 GC 线程,停顿越低体验越好。
四、GC 算法与收集器
- 三种垃圾回收算法标记清除有碎片;标记复制无碎片适合新生代;标记整理无碎片适合老年代。
- CMS 流程初始标记、并发标记、重新标记、并发清除;低停顿、有碎片、有浮动垃圾。
- G1 特点把堆分成多个 Region,优先回收垃圾多的区域,可控制最大停顿时间。
五、内存与优化
- 栈溢出 vs 堆溢出栈溢出:递归过深栈帧过多;堆溢出:对象 / 集合太多占满堆内存。
- 元空间和永久代区别永久代在堆内存易 OOM;元空间用本地直接内存,自动扩容上限更大。
- 逃逸分析优化能做栈上分配、标量替换、同步消除,减少堆对象减轻 GC 压力。
- 对象内存布局对象头、实例数据、对齐填充。
- 内存分配方式内存规整用指针碰撞;有碎片用空闲列表。
六、安卓面试常问收尾
- JVM 调优核心思路控制堆大小、优化新生代比例、减少大对象、避免频繁 Full GC、选择合适垃圾收集器。