Wrayの知识库 Wrayの知识库
首页
  • Java 基础
  • Java 集合
  • Java 并发
  • Java IO
  • JVM
  • Spring Framework
  • Spring Boot
  • Spring Cloud
  • Spring Security
  • MySQL
  • Redis
  • 计算机基础
  • 操作系统原理
  • Linux
  • MacOS
  • Windows
  • 系统工程与研究专题
  • AI 基础
  • 大模型基础
  • Prompt 工程
  • RAG 检索增强生成
  • Agent 智能体
  • AI 应用开发
  • AI 工程化
  • AI 安全与治理
  • AI 面试与设计题
  • 纸质书
  • 电子书
  • 学习课程
疑难杂症
GitHub (opens new window)
首页
  • Java 基础
  • Java 集合
  • Java 并发
  • Java IO
  • JVM
  • Spring Framework
  • Spring Boot
  • Spring Cloud
  • Spring Security
  • MySQL
  • Redis
  • 计算机基础
  • 操作系统原理
  • Linux
  • MacOS
  • Windows
  • 系统工程与研究专题
  • AI 基础
  • 大模型基础
  • Prompt 工程
  • RAG 检索增强生成
  • Agent 智能体
  • AI 应用开发
  • AI 工程化
  • AI 安全与治理
  • AI 面试与设计题
  • 纸质书
  • 电子书
  • 学习课程
疑难杂症
GitHub (opens new window)
  • Java章节编写规范
  • Java基础

  • Java集合

  • Java并发

  • Java IO

  • JVM

    • JVM概述
    • JVM基础

    • 类加载机制

    • 运行时内存

      • Java堆
        • 1. 堆的作用
        • 2. 堆是线程共享的
        • 3. 堆的分代
        • 4. G1 的堆布局
        • 5. 堆参数
        • 6. Java heap space
        • 7. 阶段小结
        • 8. 堆内对象生命周期图
        • 9. 堆容量和业务容量的关系
        • 10. 堆内存泄漏常见形态
          • 10.1 静态集合泄漏
          • 10.2 缓存无上限
          • 10.3 队列堆积
        • 11. Tips 快问快答
      • 方法区与元空间
      • 虚拟机栈本地方法栈与程序计数器
      • 对象创建与内存布局
      • 直接内存
      • OOM分类与定位
    • 垃圾回收

    • 执行引擎与优化

    • 工具与问题排查

    • 调优实践与面试

目录

Java堆

Java 堆是 JVM 中最重要的内存区域之一。绝大多数对象实例和数组都在堆上分配,垃圾回收也主要围绕堆展开。

# 1. 堆的作用

堆用于存放对象实例。

User user = new User();
int[] array = new int[1024];

user 这个引用变量可能在栈帧的局部变量表中,而真正的 User 对象在堆中。

# 2. 堆是线程共享的

堆被所有线程共享,因此多个线程可能访问同一个对象。

static User sharedUser = new User();

这也是并发安全问题产生的重要原因之一:对象在堆上共享,多个线程可能同时读写它的字段。

# 3. 堆的分代

传统分代模型中,堆可以分为:

  • 新生代。
  • 老年代。

新生代又通常包括:

  • Eden 区。
  • Survivor From。
  • Survivor To。

大多数对象朝生夕死,优先在 Eden 分配。经历多次 Minor GC 仍然存活的对象可能晋升到老年代。

# 4. G1 的堆布局

G1 不再把堆物理划分为连续的新生代和老年代,而是划分为多个 Region。

每个 Region 可以扮演不同角色:

  • Eden Region。
  • Survivor Region。
  • Old Region。
  • Humongous Region。

G1 仍然保留分代思想,但堆布局更加灵活。

# 5. 堆参数

常见堆参数:

-Xms512m
-Xmx512m

含义:

  • -Xms:初始堆大小。
  • -Xmx:最大堆大小。

生产环境中经常把二者设置为相同值,减少运行时堆扩缩容带来的抖动。

# 6. Java heap space

堆空间不足时可能出现:

java.lang.OutOfMemoryError: Java heap space

常见原因:

  • 一次性加载过多数据。
  • 集合无限增长。
  • 缓存没有淘汰。
  • 内存泄漏。
  • 堆配置过小。
  • 对象创建速度超过 GC 回收能力。

# 7. 阶段小结

Java 堆是对象存活和垃圾回收的主战场。理解堆,要同时理解对象分配、分代思想、GC 行为和内存泄漏。线上大部分 JVM 内存问题,第一现场通常就是堆。

# 8. 堆内对象生命周期图

对象创建
  │
  ▼
优先进入 Eden / TLAB
  │
  ├─ Young GC 后死亡
  │     └─ 直接回收
  │
  └─ Young GC 后存活
        │
        ▼
进入 Survivor,年龄 +1
        │
        ├─ 后续 Young GC 死亡
        │     └─ 回收
        │
        └─ 多次存活或 Survivor 放不下
              ▼
            晋升老年代
              │
              ├─ Old GC / Mixed GC 后死亡
              └─ 长期存活或泄漏

这个流程解释了很多问题:新生代回收频繁通常和对象分配速度有关,老年代持续增长通常和对象存活时间、缓存、泄漏或晋升过快有关。

# 9. 堆容量和业务容量的关系

堆大小不是越大越好。

堆配置 好处 风险
较小堆 内存占用低,GC 单次处理数据少 GC 频繁,容易 OOM
较大堆 能容纳更多对象,GC 频率可能降低 单次回收成本高,容器内存压力大
Xms=Xmx 避免运行时扩缩容 启动即占用较多内存

容量评估时要看:

  • 峰值 QPS。
  • 单请求对象分配量。
  • 缓存大小。
  • 会话数量。
  • 批处理并发。
  • GC 后稳定水位。

# 10. 堆内存泄漏常见形态

# 10.1 静态集合泄漏

private static final List<Object> DATA = new ArrayList<>();

如果不断 add 且不清理,集合会一直从 GC Roots 可达。

# 10.2 缓存无上限

缓存如果没有容量和过期策略,本质上就是一个慢性泄漏。

推荐使用 Caffeine 这类成熟缓存库,明确:

  • 最大容量。
  • 过期时间。
  • 淘汰策略。
  • 命中率监控。

# 10.3 队列堆积

生产速度大于消费速度时,队列对象持续堆积。

常见于:

  • MQ 消费慢。
  • 异步任务线程池太小。
  • 下游接口慢。
  • 无界队列。

# 11. Tips 快问快答

Q:堆越大,性能越好吗?

A:不一定。大堆可以减少部分 GC 频率,但可能增加单次回收成本,也会挤压堆外和容器内存。

Q:Full GC 后堆占用降不下来说明什么?

A:说明大量对象仍然可达,可能是正常长生命周期对象,也可能是内存泄漏。

Q:新对象一定先进 Eden 吗?

A:大多数小对象优先进入 Eden 或 TLAB。大对象、特殊分配路径、逃逸分析优化可能改变实际行为。

Q:堆 OOM 第一反应是加内存吗?

A:不是。先看是否泄漏、是否一次性加载过多数据、是否缓存无界,再决定是否扩容。

上次更新: 2026/06/24, 16:03:01
类加载问题与SPI
方法区与元空间

← 类加载问题与SPI 方法区与元空间→

Copyright © 2023-2026 Wray | 鄂ICP备2024050235号-1
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式