整理一下基本概念,因为遇到了本地线程无法创建的问题,回顾一下基本JVM的,有利于解决所需要的理论知识
一、JVM 内存模型
1. 什么是 JVM
JVM(Java Virtual Machine)本质上是:
text
Java代码的运行环境
Java代码不会直接运行在操作系统上。
而是:
text
Java代码
↓
编译成.class字节码
↓
JVM解释执行
所以 JVM 本质上是:
text
Java程序和操作系统之间的一层中间层
二、堆和栈到底是什么
这是 JVM 最核心概念。
1. 栈(Stack)
栈是:
text
线程私有的运行空间
每个线程:
text
都有自己的栈
例如:
- main线程
- Tomcat工作线程
- GC线程
都有自己的栈。
2. 栈里存什么
栈主要存:
- 方法调用
- 局部变量
- 基本类型
- 对象引用地址
例如:
java
User user = new User();
int age = 18;
运行时:
text
栈:
user = 对象地址
age = 18
3. 堆(Heap)
堆是:
text
所有线程共享的对象存储区
真正对象:
text
放在堆里
例如:
java
new User()
会进入:
text
Heap(堆)
4. 栈和堆的关系
text
栈(Stack) 堆(Heap)
user ───────────────→ User对象
name
age
phone
核心:
text
栈保存地址
堆保存真正对象
三、为什么对象不直接放栈里
因为:
text
对象可能很大
生命周期不确定
例如:
- List
- Map
- JSON
- Redis缓存对象
- Spring Bean
如果都放栈里:
text
线程内存会瞬间爆炸
所以 JVM 设计成:
| 区域 | 作用 |
|---|---|
| 栈 | 快速执行方法 |
| 堆 | 管理大量对象 |
四、线程、HTTP请求、栈之间关系
很多人误会:
text
HTTP请求来了才创建栈
其实不是。
真正是:
text
线程创建时
栈就已经存在
核心:
text
一个线程 = 一个虚拟机栈
SpringBoot 启动时
JVM 会创建很多线程:
- main线程
- GC线程
- Tomcat线程
- 定时任务线程
每个线程:
text
都有自己的栈
五、虚拟机栈 vs 本地方法栈
1. Java虚拟机栈
负责:
text
Java方法运行
例如:
- Controller
- Service
- DAO
2. 本地方法栈
负责:
text
Native方法运行
例如:
- 文件IO
- 网络IO
- 操作系统调用
- 创建线程
很多 JVM 底层能力:
text
实际上是C/C++实现
六、GC(垃圾回收)到底是什么
GC:
text
Garbage Collection
即:
text
垃圾回收
负责:
text
回收堆中的无用对象
七、OOM(内存溢出)是什么
最经典:
text
java.lang.OutOfMemoryError: Java heap space
表示:
text
堆满了
OOM 本质
不是简单:
text
GC太慢
真正本质:
text
对象创建速度
>
对象释放速度
或者:
text
对象一直被引用
无法回收
八、GC Roots 与可达性分析
这是 JVM GC 核心。
GC 并不会判断:
text
对象有没有业务价值
而是判断:
text
还能不能找到对象
1. 什么是 GC Roots
GC Roots:
text
GC扫描的起点
常见 GC Roots:
| 类型 | 示例 |
|---|---|
| 栈引用 | 方法里的变量 |
| static变量 | 静态缓存 |
| 正在运行线程 | Thread |
| 常量引用 | String常量池 |
2. GC 扫描逻辑
text
GC Roots
│
├──── 能找到对象
│ │
│ └──── 对象存活
│
└──── 找不到对象
│
└──── 对象死亡
3. 为什么 static 容易OOM
例如:
java
static Map cache = new HashMap();
因为:
text
static属于GC Roots
所以:
text
cache中的对象长期可达
GC不敢删
4. 为什么 ThreadLocal 容易泄漏
因为:
text
线程本身是GC Roots
Tomcat线程池长期存在。
所以:
text
ThreadLocalMap中的对象
长期无法回收
九、分代垃圾回收机制
JVM发现:
text
大部分对象生命周期很短
所以:
text
把不同生命周期对象分开管理
1. 堆结构
text
堆
├── 新生代
└── 老年代
十、新生代
新对象:
text
先进入新生代
结构:
text
新生代
├── Eden
├── Survivor From
└── Survivor To
对象流转
text
new对象
│
▼
Eden
│
▼
Minor GC
│
├── 死亡 → 回收
└── 存活 → Survivor
│
▼
多次存活
│
▼
老年代
十一、Minor GC 和 Full GC
1. Minor GC
触发时机:
text
Eden区满了
特点:
- 频繁
- 快
- 回收年轻对象
2. Full GC
触发时机:
text
老年代空间不足
特点:
- 很慢
- Stop The World
- 扫描整个堆
十二、GC 什么时候执行
GC 并不是:
text
方法结束立即执行
而是:
text
内存不够时触发
正确流程
text
方法结束
│
▼
对象失去引用
│
▼
变成"可回收对象"
│
▼
等待GC触发
│
▼
GC扫描
│
▼
真正回收
十三、类加载机制
Java类不会自动进入JVM。
必须:
text
ClassLoader加载
JVM默认三层类加载器
text
Application ClassLoader
↑
Extension ClassLoader
↑
Bootstrap ClassLoader
各自职责
| 类加载器 | 负责内容 |
|---|---|
| Bootstrap | JDK核心类 |
| Extension | 扩展类库 |
| Application | 业务代码 |
十四、双亲委派机制
核心思想:
text
加载类时
先问父加载器
父加载不了
自己再加载
加载流程
text
Application收到请求
│
▼
先问Extension
│
▼
Extension问Bootstrap
│
▼
Bootstrap能加载?
│
┌─┴───────┐
│ │
能 不能
│ │
Bootstrap 返回下层
加载 │
▼
最终Application加载
十五、双亲委派为什么重要
1. 防止核心类被篡改
例如:
java
java.lang.String
只能由:
text
Bootstrap加载
业务代码无法替换。
2. 防止类重复加载
JVM 中:
text
类名 + ClassLoader
=
唯一类
3. 保证安全隔离
Tomcat 能同时运行多个项目:
text
因为每个项目有自己的ClassLoader
十六、今天最核心的理解
JVM 内存
text
栈:线程私有
堆:对象存储
GC
text
GC判断对象是否死亡
看的是:
还能不能从GC Roots找到
分代GC
text
不同生命周期对象
采用不同回收策略
双亲委派
text
本质是:
优先级 + 安全机制
防止:
- 核心类被覆盖
- 类重复加载
- 恶意注入
十八、现实世界类比总结(帮助真正理解)
1. JVM 像什么?
JVM 可以理解成:
text
Java程序的"操作系统"
它负责:
- 管理内存
- 管理线程
- 管理对象
- 管理类加载
- 管理垃圾回收
就像:
text
一个大型公司的总管理系统
2. 栈(Stack)像什么?
栈像:
text
每个员工自己的办公桌
特点:
- 私有
- 快速
- 临时
- 方法结束立刻清理
所以:
text
一个线程 = 一张办公桌
3. 堆(Heap)像什么?
堆像:
text
公司公共仓库
所有线程:
text
共享这个仓库
真正的大对象:
- List
- Map
- Bean
- DTO
- JSON
都放在这里。
4. 对象引用像什么?
代码:
java
User user = new User();
本质像:
text
办公桌上放着"仓库货架编号"
即:
text
栈里放地址
堆里放真正对象
5. GC 像什么?
GC 像:
text
公司保洁 + 仓库管理员
负责:
text
清理没人使用的物品
6. GC Roots 像什么?
GC Roots 像:
text
公司总台登记系统
GC 会从"总台记录"开始查:
text
这个东西还有没有人能找到
如果:
text
还能找到
说明:
text
对象还活着
否则:
text
对象死亡
7. Minor GC 像什么?
Minor GC 像:
text
快递临时区清理
因为:
text
大部分快递当天就会拿走
所以:
text
清理特别快
8. 老年代像什么?
老年代像:
text
公司长期仓库
放:
- 核心设备
- 长期资产
- 大型机器
特点:
text
东西多
清理慢
9. Full GC 像什么?
Full GC 像:
text
整个公司停工大扫除
所以:
text
会暂停业务
即:
text
Stop The World
10. 双亲委派像什么?
双亲委派像:
text
公司逐级审批制度
基层:
text
不能直接覆盖总部规定
必须:
text
先问上级
这就是:
text
先委派父加载器
11. Bootstrap ClassLoader 像什么?
Bootstrap 类加载器像:
text
公司董事长 / 国家中央系统
负责:
text
最核心最重要的类
例如:
- String
- Object
- Thread
- Class
这些:
text
绝对不能被业务代码替换
12. ThreadLocal 为什么容易泄漏?
ThreadLocal 像:
text
员工工位抽屉
如果:
text
员工一直不离职
抽屉里的东西:
text
永远不会被清理
Tomcat线程池就是这样。
13. OOM 像什么?
OOM 像:
text
仓库塞满了
可能因为:
- 东西产生太快
- 垃圾清理太慢
- 有人一直占着不丢
最终:
text
仓库彻底放不下
十九、最终一句总结
JVM 最核心其实只有一句话:
text
对象如何创建
对象如何存活
对象如何死亡
而:
- 内存模型
- GC
- 类加载
本质上都是围绕:
text
对象生命周期管理
展开的。