JVM 内存与 GC 概览
运行时数据区直觉、堆上对象与 GC 基本目标:先正确测量再谈调优,并标注实现相关性。
#type / concept
#status / growing
#tech / dev
#resource / java
[!info] 关联笔记
JVM 内存与 GC 概览
这个概念为什么出现
OOM、频繁停顿、堆配置争论都指向内存与 GC。先建立对象在堆、帧在栈、GC 回收不可达对象的模型,再谈收集器名称与参数。
[!abstract] 一句话理解 对象主要在堆分配;GC 回收不可达对象;具体分代/收集器/停顿行为高度实现相关,必须测量后调优。
最小可观察示例
场景:分配大量临时对象观察程序仍可结束(示意)
public class AllocChurn {
public static void main(String[] args) {
long sum = 0;
for (int i = 0; i < 1_000_00; i++) {
sum += ("id-" + i).length(); // 产生临时字符串
}
System.out.println(sum);
}
}
javac AllocChurn.java && java -Xms32m -Xmx32m AllocChurn
期望:打印正整数并正常退出(具体 sum 固定可算)。
可用 java -Xlog:gc*:file=gc.log(版本支持时)观察 GC 日志——解读依赖实现。
结合场景再看三个关注点
- 临时对象靠 GC 回收,不是手动 free。
- 堆上限
-Xmx是常见容量阀。 - 日志证明有回收活动,不代表你需要立刻调参。
核心概念与准确模型
1. 运行时数据区(教学模型)
- 堆:对象实例
- 栈:帧、局部变量
- 元空间:类元数据(HotSpot 常见)
- PC/本地栈等
2. 可达性
GC Root 出发不可达 → 可回收(含最终化等历史细节慎用)。
3. 收集器
Serial/Parallel/G1/ZGC… 名称与默认随 JDK 版本变。
边界情况与反直觉行为
- 内存泄漏常是“仍可达但不该可达”(缓存、监听器)。
- 堆外内存(直接内存、JNI)不在同一仪表盘。
- 最终化
finalize已过时,不应用。
常见误区
[!warning] 常见误区:一上来抄 GC 参数大全 先修分配与泄漏,再用指标驱动。
工程实践
- 固定容器内存与
-Xmx关系。 - 观察分配速率、停顿、堆占用。
- 用 MAT/jcmd/jfr 定位保留路径。
- 版本升级后重测默认收集器变化。
本节总结
- 堆对象 + 可达性回收
- 实现相关细节要标注
- 测量优先于调参
自测题
- 栈上装的是对象本身吗?
- 为什么“泄漏”在 GC 语言里仍可能发生?
参考答案
- 栈帧持有引用/基本类型局部量;对象实例通常在堆。
- 对象仍被无意引用保持可达,GC 无法收。
延伸阅读与资料来源
| 资料 | 类型 | 支撑内容 |
|---|---|---|
| HotSpot GC Tuning Guide | 官方 | 实现向导 |
| JVMS Runtime Data Areas | 规范 | 数据区概念 |