← [ BACK_TO_NOTES ]

JVM 内存与 GC 概览

运行时数据区直觉、堆上对象与 GC 基本目标:先正确测量再谈调优,并标注实现相关性。

#concept #growing #dev #java

[!info] related notes

JVM 内存与 GC 概览

这个概念为什么出现

OOM、频繁停顿、堆配置争论都指向内存与 GC。先建立对象在堆、帧在栈、GC 回收不可达对象的模型,再谈收集器名称与参数。

[!abstract] 一句话理解 对象主要在堆分配;GC 回收不可达对象;具体分代/收集器/停顿行为高度实现相关,必须测量后调优。

最小可观察示例

场景:分配大量临时对象观察程序仍可结束(示意)

public class AllocChurn {
    public static void main(String[] args) {
        long sum = 0;
        for (int i = 0; i < 100_000; i++) {
            sum += ("id-" + i).length(); // 源码产生临时字符串,实际分配可能被 JIT 优化
        }
        System.out.println(sum);
    }
}
javac AllocChurn.java && java -Xms32m -Xmx32m AllocChurn

在 JDK 21 中期望打印 788890 并正常退出。HotSpot 可用完整命令 java -Xms32m -Xmx32m -Xlog:gc*:file=gc.log AllocChurn 观察日志。这个短程序不保证触发 GC;正常退出也不能证明每个临时对象都实际分配过或已被回收。

结合场景再看三个关注点

  1. 临时对象靠 GC 回收,不是手动 free。
  2. -Xmx 限制 Java 堆,不等于 JVM 进程或容器总内存上限。
  3. 检查日志中的具体 GC 事件;只有初始化信息不代表发生过回收,有 GC 也不代表需要立刻调参。

核心概念与准确模型

1. 运行时数据区(教学模型)

  • 堆:对象实例
  • JVM 栈:调用帧、局部变量与操作数栈;局部变量可含基本值或对象引用。
  • 方法区是 JVMS 的逻辑区域;HotSpot 元空间主要承载类元数据,使用本地内存,不能把两者当作完全同义词。
  • PC/本地栈等

2. 可达性

从 GC roots 不再强可达的对象才可能进入后续引用处理/回收流程;弱、软、虚引用另有语义。可回收不等于立即回收,GC 也不负责及时关闭文件、连接或锁。JIT 可能通过逃逸分析和标量替换消除分配,教学数据区模型不规定每个值的物理位置。

3. 收集器

Serial/Parallel/G1/ZGC… 名称与默认随 JDK 版本变。

边界情况与反直觉行为

  1. 内存泄漏常是“仍可达但不该可达”(缓存、监听器)。
  2. 堆外内存(直接内存、JNI)不在同一仪表盘。
  3. finalization 自 JDK 18 起已标记待移除,不保证及时执行;资源关闭应使用明确生命周期和 try-with-resources。

常见误区

[!warning] 常见误区:一上来抄 GC 参数大全 先修分配与泄漏,再用指标驱动。

工程实践

  1. 为容器预算堆、线程栈、元空间、代码缓存、直接内存和其他本地开销,不能把全部容器限额都给 Xmx。
  2. 观察分配速率、停顿、堆占用。
  3. 用 MAT/jcmd/jfr 定位保留路径。
  4. 版本升级后重测默认收集器变化。

本节总结

  • 堆对象 + 可达性回收
  • 实现相关细节要标注
  • 测量优先于调参

自测题

  1. 栈上装的是对象本身吗?
  2. 为什么“泄漏”在 GC 语言里仍可能发生?
参考答案
  1. 栈帧持有引用/基本类型局部量;对象实例通常在堆。
  2. 对象仍被无意引用保持可达,GC 无法收。

延伸阅读与资料来源

资料类型支撑内容
HotSpot GC Tuning Guide官方实现向导
JVMS Runtime Data Areas规范数据区概念
创建于 2026/7/15 更新于 2026/10/6
Digital Biome
Access

键盘导航

j / k / ↑ / ↓
选择对象
Enter / o
打开选择
/ 或 Ctrl+K
全站搜索
i / f / 1–4
筛选当前列表
g → h / l / p / t / a
首页 / 笔记 / 项目 / 工具 / About
r → 1–9
打开所选对象的关联
u
返回上一页
Esc
关闭浮层 / 取消命令;输入框内清空文本