八股(四)JVM
目录
😺Java 内存区域
JVM 哪个内存区域不会发生 OutOfMemoryError(OOM)
字符串常量池的作用是?
😺JVM 垃圾回收
如何判断对象是否死亡?
垃圾回收算法
😺问题排查
😺Java 内存区域
Java 内存区域指的是 JVM 在执行 Java 程序时,把内存划分成的不同功能区域。
线程私有区域(每个线程独立):
- 程序计数器(PC Register):记录当前线程执行到哪一条字节码。
- 虚拟机栈(JVM Stack):存储方法执行过程(栈帧)。
- 本地方法栈(Native Stack):执行 native 方法(C/C++)。
线程共享区域(所有线程共享):
- 堆(Heap):存放所有对象实例。
- 方法区(Method Area):类信息、静态变量、常量池、方法字节码。
JDK 1.8 变化重点:方法区实现变成元空间(Metaspace),不在 JVM 内存,而是使用本地内存(Native Memory)。
JVM 哪个内存区域不会发生 OutOfMemoryError(OOM)
程序计数器。
程序计数器用于记录当前线程执行的字节码指令位置,通过改变计数器的值来控制程序的流程执行,包括顺序执行、分支、循环和异常处理等。
在多线程环境下,每个线程都需要独立的程序计数器,用于记录各自的执行位置,从而在线程切换后能够恢复到正确的执行状态。
由于程序计数器占用内存极小、生命周期随线程创建和销毁而变化,并且不涉及动态内存分配,因此不会发生内存溢出。
字符串常量池的作用是?
字符串常量池是 JVM 为了提升性能和减少内存消耗,为字符串专门开辟的一块区域,用于存储字符串字面量,避免重复创建相同内容的字符串对象。
当创建字符串时,如果常量池中已存在该字符串,则直接返回引用;否则将其加入常量池。
😺JVM 垃圾回收
如何判断对象是否死亡?
可达性分析算法。从 GC Roots 出发,向下搜索可达对象。如果一个对象无法通过引用链从 GC Roots 访问到,就认为它“死亡”。
GC Roots 主要包括虚拟机栈中的局部变量、本地方法栈中的引用、方法区中的静态变量和常量、被同步锁持有的对象以及 JNI 引用等。
即使对象在可达性分析中不可达,也不会立即被回收,而是会经历一次标记和筛选过程,只有在无法重新建立引用关系时,才会被真正回收。
Q:为什么引用计数法不被采用?
A:因为无法解决循环引用问题,会导致内存泄漏。
Q:GC Roots 为什么要这些对象?
A:因为它们处于程序运行核心路径中,代表“正在使用”的对象。
Q:对象一定会被 GC 回收吗?
A:不一定,需要经历可达性分析 + finalize 筛选。
垃圾回收算法
1)标记-清除算法(Mark-Sweep)
分两步:
- 标记存活对象
- 清除未标记对象
缺点:效率低、产生内存碎片。
2)复制算法(Copying)
将内存一分为二,只用一半,From区 → To区(存活对象复制)。
优点:没有内存碎片、分配速度快、适合新生代。
缺点:浪费内存(50% 内存被闲置)、对象存活多时效率低(复制成本极高)。
3)标记-整理算法(Mark-Compact)
分三步:
- 标记存活对象
- 向一端移动存活对象
- 清理边界外空间
优点:没有碎片、内存利用率高。
缺点:移动对象成本高。
4)分代收集算法(现代主流思想)
不同生命周期对象采用不同算法。
新生代(Young):对象“死得快”、存活率低,适合复制算法。
老年代(Old):对象存活率高、回收频率低,适合标记-整理。
😺问题排查
- 内存问题(OOM、泄漏)
- 线程问题(死锁、阻塞)
- 性能问题(CPU过高、GC频繁)
Java 性能优化和问题排查工具主要分为三类。
第一类是 JDK 自带的可视化工具,例如 JConsole 和 VisualVM,可以用于监控 JVM 的内存、线程、GC 等运行状态,其中 VisualVM 功能更强大,还支持 Heap Dump 分析。
第二类是 JDK 命令行工具,包括 jps 用于查看 Java 进程,jstat 用于监控 GC 状态,jmap 用于生成堆内存快照,jstack 用于查看线程栈信息排查死锁问题。
第三类是第三方工具,例如 MAT 用于分析 Heap Dump,定位内存泄漏;GCViewer 和 GCeasy 用于分析 GC 日志;JProfiler 用于性能分析;Arthas 是阿里开源的线上诊断工具,可以在不重启应用的情况下实时查看线程、内存和方法调用情况。
在实际排查中,如果发生死锁,可以通过 jstack 查看线程栈,通常会出现 Found one Java-level deadlock 字样;如果发生 OutOfMemoryError,可以通过 jmap 导出 Heap Dump,再用 MAT 分析内存泄漏问题。
Q:线上 CPU 100% 怎么排查?
A:top 找进程 → jstack 找线程 → 定位死循环或锁竞争
