IWA
2025-12-03
点 赞
0
热 度
5
评 论
0

Java 性能优化实战 第 3 篇:JVM 内存结构与 GC 原理


——你必须先搞懂的底层基础(GC 调优必读)

GC 调优离不开对 JVM 内存结构的理解,本篇将从:

JVM 内存结构
对象创建与逃逸流程
垃圾回收算法
GC 触发条件
各类垃圾收集器原理(重点:G1 / ZGC)

这 5 个方面给你建立完整知识体系。


🧩 一、JVM 内存结构(JAVA 8+)

自从 Java 8 移除永久代(PermGen)后,JVM 的结构更清晰了:

【线程私有】
  - 程序计数器 (Program Counter)
  - JVM 栈 (Stack)
  - 本地方法栈 (Native Stack)

【线程共享】
  - 堆 (Heap)
  - 元空间 (Metaspace)
  - 代码缓存 (Code Cache)

我们重点讲 Heap + Metaspace,因为 GC 主要发生在堆。

✔ 1. 堆(Heap)

堆是 JVM 最大、最重要 的区域,存放所有对象。

结构如下:

Heap
 ├── Young Generation(新生代)
 │     ├── Eden
 │     ├── Survivor S0
 │     └── Survivor S1
 └── Old Generation(老年代)
  • 99% 的对象在 Eden 创建

  • Survivor 用于对象在 Young 区之间“拷贝”

  • 经过多次 Minor GC 后,长寿命的对象进入 Old 区


✔ 2. 元空间(Metaspace)

Java 8 之后,类元信息存放在 本地内存 里,不再受堆大小影响。

元空间撑爆一般有两类原因:

  • 动态生成类过多(如 CGLib、大量反射生成代理类)

  • Web 容器频繁重启导致类无法卸载

元空间 OOM 排查重点看:

jcmd <pid> VM.class_hierarchy

⚙️ 二、Java 对象创建与分配流程

一个对象从创建到晋升的完整过程如下:

new → Eden 分配 → Minor GC → Survivor 复制 → 多次 Survivor → Old 区晋升

核心规则:

✔ 1. 对象优先分配在 Eden

只要 Eden 有足够空间,JVM 会使用 TLAB(线程私有缓冲区)快速分配对象。

✔ 2. 大对象直接进入 Old 区

比如:

  • 大数组

  • 大字符串

  • 大 Map

可通过:

-XX:PretenureSizeThreshold

进行配置(仅部分 GC 生效)。

✔ 3. 长寿命对象晋升到 Old 区

通常经历 15 次 Minor GC 后晋升,可通过:

-XX:MaxTenuringThreshold

控制;G1/ZGC 是动态调整,无需设置。


♻️ 三、JVM 中的垃圾回收算法(理解 GC 核心原理)

GC 的根本问题:

认识哪些对象“还活着”?

JVM 采用 可达性分析算法(Reachability Analysis)

从 GC Roots 开始找可达对象,不能被访问的对象才是“垃圾”。

GC Roots 包括:

  • 栈帧里的引用

  • 本地方法引用

  • 静态成员变量

  • 常量池

  • JVM 内部引用


GC 算法核心包含三个:

✔ 1. 标记-清除(Mark-Sweep)

流程:

标记 → 清除

缺点:产生内存碎片。

用于:CMS 老年代等。


✔ 2. 标记-压缩(Mark-Compact)

标记 → 移动对象 → 压缩到一起

减少碎片。

用于:Serial / Parallel Old 以及 G1、ZGC 等现代 GC。


✔ 3. 复制算法(Copying)

Young 区的算法:

Eden → Survivor1
Survivor1 → Survivor2

适用于:

  • 新生代存活率低

  • 复制成本低


🔥 四、GC 类型与触发条件(为什么 GC 发生?)

✔ 1. Minor GC(年轻代 GC)

什么时候发生?

当 Eden 空间不足。

特点:

  • 速度快

  • 不会影响 Old 区

  • 停顿时间短(几十毫秒级)

Minor GC 是“常态”,不是坏事。


✔ 2. Major GC / Full GC(重点关注)

触发:

  • Old 区空间不足

  • 元空间不足

  • 显式 System.gc()(可能被禁用)

  • 大对象分配失败

  • CMS/G1 触发 Mixed GC

Full GC 成本高(100ms ~ 1s+),必须重点监控。


🏆 五、现代垃圾回收器(GC 的真正核心)

不同 GC 适用于不同场景。


✔ 1. Parallel GC(吞吐量优先)

特点:

  • 默认的堆为内存大、CPU 多的场景(以前是默认)

  • 追求吞吐量

  • 停顿时间较长

适合:

  • 批处理

  • 后台任务

  • 延迟要求不高的系统


✔ 2. CMS(低延迟)

特点:

  • 并发标记

  • 减少 STW

  • 但会产生碎片

缺点使其在 Java 9 后开始被 G1 取代。


✔ 3. G1(Java 11+ 默认)

重点:分区(Region)+ 并发 + 可预测停顿

结构:

把整个堆切成多个 Region:
Young / Old 都是多个 Region 的集合

优势:

  • 支持大堆(4G~64G 甚至以上)

  • Mixed GC 效率高

  • 停顿可控

需要理解这两个概念:

(1) Mixed GC

同时回收 Young + Old(部分 Region)

(2) RSet(记忆集)

记录 Old → Young 的引用,减少扫描范围。


✔ 4. ZGC(毫秒级低延迟)

这是 GC 的未来方向。

核心理念:

并发整理
读屏障
染色指针(Colored Pointer)
暂停 < 1ms(几乎固定)

适合:

  • 低延迟服务

  • 高并发场景

  • 大堆(32GB ~ TB 级别)

ZGC + 虚拟线程(Loom)= Java 未来方向。


🧠 六、为什么系统会卡顿?(从 GC 角度看)

常见原因:

❌ Minor GC 太频繁

→ Eden 太小 / 大量瞬时对象

❌ Full GC 频繁

→ Old 区溢出 / 内存泄漏

❌ CMS/G1 回收跟不上

→ 对象创建太快

❌ 元空间不足

→ 大量动态代理类


📌 七、如何选择正确的 GC?

场景

推荐 GC

普通 Web 服务

G1(默认)

高并发低延迟(银行、券商)

ZGC

批处理、后台任务

Parallel

老系统

CMS(逐步迁移)


🎯 八、总结:理解 GC 才能真正优化性能

本篇把 JVM 内存结构、GC 原理、对象分配全都讲清楚。
当你理解:

  • 对象为什么进入 Old 区

  • GC 什么时候发生

  • 为什么会 Full GC

  • 为什么服务卡顿

你就能真正开始 GC 调优了。


用键盘敲击出的不只是字符,更是一段段生活的剪影、一个个心底的梦想。希望我的文字能像一束光,在您阅读的瞬间,照亮某个角落,带来一丝温暖与共鸣。

IWA

infp 调停者

具有版权性

请您在转载、复制时注明本文 作者、链接及内容来源信息。 若涉及转载第三方内容,还需一同注明。

具有时效性

文章目录

IWA的艺术编程,为您导航全站动态

40 文章数
9 分类数
10 评论数
34标签数
最近评论
IWA

IWA


👍

M丶Rock

M丶Rock


😂

M丶Rock

M丶Rock


感慨了

M丶Rock

M丶Rock


厉害了

M丶Rock

M丶Rock


6666666666666666666