本文将从 JVM 内存模型入手,深入剖析各个区域的作用、GC 的运行机制与常见算法,并结合源码与面试思维,带你掌握 JVM 的底层世界。
JVM 将内存划分为若干区域,每个区域有其独立职责:
-Xms
和 -Xmx
设置堆初始与最大值。public class HeapOOM {
public static void main(String[] args) {
List<byte[]> list = new ArrayList<>();
while (true) {
list.add(new byte[1024 * 1024]);
}
}
}
备注:
Q:什么情况下会抛出 OutOfMemoryError?
A:当申请内存超出堆最大容量时,GC 无法回收足够空间就会 OOM。
GC 并非作用于所有内存区域,而是只关注堆和方法区。
标记-清除
复制算法
标记-整理
分代回收
JVM 将堆划分为:
新生代(Young Generation)
老年代(Old Generation)
具体如:
Young Gen:
Eden + SurvivorFrom + SurvivorTo
Old Gen:
Tenured
收集器 | 作用代 | 算法 | 适用场景 |
---|---|---|---|
Serial | 新生代 | 复制 | 单线程小应用 |
ParNew | 新生代 | 复制 | 多线程环境 |
CMS | 老年代 | 标记清除 | 响应快 |
G1 | 整堆 | 分区整理 | 低延迟大内存 |
ZGC | 整堆 | 并发标记复制 | 超大内存场景 |
# 示例:开启 G1 收集器
-XX:+UseG1GC
-XX:+PrintGCDetails -Xloggc:gc.log
典型日志解读:
[GC (Allocation Failure) [PSYoungGen: 512K->128K(768K)] 1024K->512K(1536K)]
含义:
Young GC 发生
Eden 区释放
堆总容量变化
以 G1
为例:
// G1GC 内部空间定义
class G1CollectedHeap : public CollectedHeap {
...
HeapRegion* _regions;
}
在 G1Policy::record_collection_pause_end()
中控制回收行为:
void G1Policy::record_collection_pause_end(...) {
update_young_list_target_length();
update_old_gen_estimates();
}
-Xms2g -Xmx2g
-XX:+UseG1GC
Q1:GC 会回收哪些区域?
✅ A1:只会回收堆和方法区(Java 8 开始为元空间 MetaSpace)。
Q2:Minor GC 和 Full GC 有什么区别?
✅ A2:Minor 仅作用于新生代,速度快;Full 会触发老年代,速度慢。
Q3:如何定位 OOM 的位置?
✅ A3:结合 -XX:+HeapDumpOnOutOfMemoryError 输出内存快照,用 MAT 工具分析。
本文从 JVM 的内存模型出发,详细解析了堆结构、GC 算法与主流收集器,结合日志调优与源码进行系统讲解,并融入了面试视角与实战经验。掌握 JVM 原理是 Java 工程师高阶进阶的必经之路。
后续预告:下一篇将深入分析 Java 类加载机制及其破坏与替代方案,敬请期待。