最新下载
热门教程
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
第三章:Java 内存模型 JMM 与运行时数据区
时间:2026-06-03 10:05:01 编辑:袖梨 来源:一聚教程网
Java程序员在遇到内存溢出、栈溢出或频繁GC等问题时,都需要深入理解JVM内存结构。本文将系统讲解运行时数据区与内存模型,帮助掌握内存管理的核心知识。

OutOfMemoryError
StackOverflowError
频繁Full GC
内存泄漏
线程安全问题
CPU 100%
这些问题最终都指向:
JVM内存
例如:
List list = new ArrayList<>();while (true) {
list.add(new User());
}
运行后:
java.lang.OutOfMemoryError: Java heap space
为什么会报错?
因为:
堆内存被占满了
所以学习 JVM,首先必须搞懂内存结构。
二、JVM 运行时数据区
当 JVM 启动时,会创建运行时数据区(Runtime Data Area)。
官方结构图:
JVM Runtime Data Area 线程共享
┌─────────────────────┐
│ Heap │
├─────────────────────┤
│ Method Area │
└─────────────────────┘
线程私有
┌─────────────────────┐
│ Program Counter │
├─────────────────────┤
│ Java Stack │
├─────────────────────┤
│ Native Method Stack │
└─────────────────────┘
分为两大类:
线程共享
所有线程共同拥有:
Heap(堆)
Method Area(方法区)
线程私有
每个线程独立拥有:
程序计数器
虚拟机栈
本地方法栈
三、程序计数器(Program Counter Register)
这是 JVM 最小的一块内存。
作用:
记录当前线程执行到哪条字节码指令
例如:
public void test() {
int a = 1;
int b = 2;
int c = a + b;
}
JVM执行过程:
0: iconst_1
1: istore_12: iconst_2
3: istore_24: iload_1
5: iload_2
6: iadd
7: istore_3
程序计数器记录:
当前执行位置
例如:
当前执行到第5条指令
为什么每个线程都需要程序计数器?
因为 JVM 支持多线程。
例如:
线程A
线程B
线程C
CPU不断切换:
A → B → C → A → B
切换回来时必须知道:
上次执行到哪里
因此每个线程都必须拥有独立程序计数器。
四、Java 虚拟机栈(Java Virtual Machine Stack)
这是面试最高频知识点之一。
什么是栈?
每个线程启动时:
创建一个虚拟机栈
每调用一个方法:
创建一个栈帧(Stack Frame)
例如:
public static void main(String[] args) {
test();
}public static void test() {
int age = 18;
}
执行过程:
main()
│
▼
test()
栈结构:
┌──────────┐
│ test() │
├──────────┤
│ main() │
└──────────┘
五、栈帧结构
每个方法对应一个栈帧。
┌────────────────────┐
│ Local Variables │
├────────────────────┤
│ Operand Stack │
├────────────────────┤
│ Dynamic Linking │
├────────────────────┤
│ Return Address │
└────────────────────┘
局部变量表
例如:
public void test() {
int age = 18;
String name = "Tom";
}
存放:
age
name引用
操作数栈
JVM计算使用。
例如:
int c = a + b;
执行过程:
push a
push b
add
pop
类似:
1
2
+
=
3
六、StackOverflowError 原理
经典面试题。
代码:
public void test() {
test();
}
执行:
test()
└─ test()
└─ test()
└─ test()
...
栈不断增长:
┌──────┐
│test │
├──────┤
│test │
├──────┤
│test │
├──────┤
│test │
└──────┘
最终:
java.lang.StackOverflowError
七、本地方法栈(Native Method Stack)
服务于:
native
关键字修饰的方法。
例如:
public native void start0();
Thread源码:
start()
↓
start0()
最终进入:
C++
Linux
Windows API
执行。
八、堆(Heap)
JVM中最大的一块内存。
也是 GC 最主要工作区域。
堆存储什么?
所有对象:
new User()new ArrayList()new HashMap()
都在堆中。
例如:
User user = new User();
内存:
Stack
└─ user引用Heap
└─ User对象
九、对象创建过程
代码:
User user = new User();
发生了什么?
第一步
检查类是否加载:
User.class
未加载:
ClassLoader加载
第二步
堆中分配内存:
Heap
┌─────────┐
│ User对象 │
└─────────┘
第三步
初始化对象:
name = null;
age = 0;
第四步
执行构造函数:
public User() {
this.age = 18;
}
第五步
返回引用:
user
保存到栈。
十、方法区(Method Area)
JDK8以前:
Permanent Generation(PermGen)
JDK8以后:
Metaspace(元空间)
存储内容
类元数据:
public class User {
}
存放:
类名
字段信息
方法信息
字节码
运行时常量池
示例
public class User { private String name; public void hello() { }
}
方法区保存:
User类结构
hello方法信息
name字段信息
十一、运行时常量池
属于方法区的一部分。
例如:
String s = "hello";
字符串常量:
"hello"
会进入:
String Constant Pool
例如:
String a = "abc";
String b = "abc";
实际上:
a
---> "abc"
/
b
共享同一个对象。
十二、JMM(Java Memory Model)是什么?
很多人把 JVM 内存结构和 JMM 混淆。
实际上:
JVM Runtime Data Area
解决:
内存如何划分
问题。
JMM
解决:
线程之间如何访问内存
问题。
十三、为什么需要 JMM?
假设:
private boolean flag = false;
线程A:
flag = true;
线程B:
while (!flag) {}
理论上:
线程B应该结束循环
但实际上:
可能永远循环
为什么?
因为 CPU 缓存。
十四、JMM 核心结构
Main Memory
│
┌──────────┴──────────┐
│ │
Thread A Thread B
Working Memory Working Memory
每个线程:
有自己的工作内存
不能直接访问其他线程内存。
执行流程:
主内存
↓
工作内存
↓
修改
↓
刷新主内存
十五、volatile 如何解决可见性?
代码:
private volatile boolean flag = false;
线程A:
flag = true;
JMM保证:
立即刷新主内存
线程B:
读取主内存最新值
因此:
while循环结束
十六、JMM 三大特性
1 原子性(Atomicity)
例如:
count++;
实际上:
读取
+
1
写回
不是原子操作。
2 可见性(Visibility)
线程A修改变量:
flag = true;
线程B能够立即看到。
3 有序性(Ordering)
JVM和CPU会优化:
指令重排
JMM保证:
在规则范围内有序
十七、面试高频问题
JVM内存结构有哪些?
程序计数器
虚拟机栈
本地方法栈
堆
方法区
堆和栈有什么区别?
栈:
线程私有
方法调用
局部变量
堆:
线程共享
对象实例
GC管理
为什么会 StackOverflowError?
递归过深
栈帧过多
导致栈空间耗尽。
为什么会 OOM?
堆内存不足
元空间不足
直接内存不足
JMM 和 JVM 内存结构有什么区别?
JVM内存结构:
关注内存区域划分
JMM:
关注线程间共享变量访问规则
本章总结
掌握运行时数据区与JMM后,便理解了JVM内存管理的核心基础。下一章将深入垃圾收集原理,涵盖对象判定、GC类型及主流收集器选择,这是面试与调优的关键内容。
相关文章
- Gemini下载怎么用?3个步骤搞定 06-04
- Gemini API密钥怎么申请?2026实测4种渠道对比 06-04
- 壹深圳app如何查看回放 06-04
- 我亲测了Gemini学生认证,全流程+踩坑记录 06-04
- Gemini 3.0使用教程 vs 4.0:3大区别与选择建议 06-04
- 干紫菜是紫色的炖汤后变成了绿色这是买到假紫菜了吗 小鸡宝宝考考你蚂蚁庄园3月9日答案 06-04