01-JVM 内存模型与 GC 原理解析

JVM 内存模型与 GC 原理解析

本文将从 JVM 内存模型入手,深入剖析各个区域的作用、GC 的运行机制与常见算法,并结合源码与面试思维,带你掌握 JVM 的底层世界。


一、JVM 内存模型(Java Memory Model)

JVM 将内存划分为若干区域,每个区域有其独立职责:

  • 程序计数器(线程私有)
  • 虚拟机栈(线程私有)
  • 本地方法栈
  • 堆(Heap)
  • 方法区(MetaSpace)

二、重点区域解析

2.1 堆(Heap)

  • 所有对象实例、数组存放在堆中。
  • -Xms-Xmx 设置堆初始与最大值。
  • GC 的核心目标区域。
java 复制代码
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(垃圾回收)机制解析

GC 并非作用于所有内存区域,而是只关注堆和方法区。

3.1 常见垃圾回收算法

  • 标记-清除

  • 复制算法

  • 标记-整理

  • 分代回收

3.2 分代回收机制

JVM 将堆划分为:

  • 新生代(Young Generation)

  • 老年代(Old Generation)

具体如:

yaml 复制代码
Young Gen:
  Eden + SurvivorFrom + SurvivorTo
Old Gen:
  Tenured

四、主流 GC 垃圾收集器

收集器 作用代 算法 适用场景
Serial 新生代 复制 单线程小应用
ParNew 新生代 复制 多线程环境
CMS 老年代 标记清除 响应快
G1 整堆 分区整理 低延迟大内存
ZGC 整堆 并发标记复制 超大内存场景
ruby 复制代码
# 示例:开启 G1 收集器
-XX:+UseG1GC

五、GC 日志分析与调优

ruby 复制代码
-XX:+PrintGCDetails -Xloggc:gc.log

典型日志解读:

scss 复制代码
[GC (Allocation Failure) [PSYoungGen: 512K->128K(768K)] 1024K->512K(1536K)]

含义:

  • Young GC 发生

  • Eden 区释放

  • 堆总容量变化

六、源码视角下的 GC 行为

G1为例:

java 复制代码
// G1GC 内部空间定义
class G1CollectedHeap : public CollectedHeap {
    ...
    HeapRegion* _regions;
}

G1Policy::record_collection_pause_end() 中控制回收行为:

cpp 复制代码
void G1Policy::record_collection_pause_end(...) {
    update_young_list_target_length();
    update_old_gen_estimates();
}

七、JVM 常见调优策略

  • 设置合适堆大小,避免频繁 Full GC:
bash 复制代码
-Xms2g -Xmx2g
  • 优化 GC 策略(G1 替代 CMS):
bash 复制代码
-XX:+UseG1GC
  • 利用 JVM 工具链(如 jmap、jstat、VisualVM)

📌 面试问答分析(Q&A)

💬 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 类加载机制及其破坏与替代方案,敬请期待。

相关推荐
爱勇宝5 小时前
第 1 章:别把“需求文档”当成真正的需求
前端·后端·程序员
IT_陈寒9 小时前
闭包陷阱让我加了两天班,JavaScript你真行
前端·人工智能·后端
易协同低代码10 小时前
通达OA核心类库TD类深度解析
后端
Gopher_HBo10 小时前
Go语言学习笔记(十八)Gin处理Session
后端
谭光志11 小时前
工具塞满上下文窗口怎么办?深度拆解 AI Agent Tool Search 按需加载实现原理
前端·后端·ai编程
她说..11 小时前
Java 默认值设置方式
java·开发语言·后端·springboot
foggyprojects11 小时前
从0开始,一句话启动AI DataAgent
后端·数据分析·ai编程
郡杰12 小时前
一些基础和问题解决
后端
陈随易12 小时前
前端项目部署只要30秒
前端·后端·程序员
YIAN12 小时前
从零手写文件读取 MCP 服务:一文吃透 Model Context Protocol 全链路通信原理
前端·后端·mcp