【JVM 模型】
·
一、类加载机制(ClassLoader)
1.类加载过程
加载 → 验证 → 准备 → 解析 → 初始化 → 使用 → 卸载
1.1 加载
- 通过类的全限定名获取。class字节码
- 转换为class对象
- 放入方法区(MetaSpace)
来源:
- 文件系统
- jar
- 网络
- 动态生成(ASM、CGLIB)
1.2 验证
保证class文件安全性
- 文件格式校验
- 元数据校验
- 字节码校验
- 符号引用校验
防止JVM被恶意字节码攻击
1.3 准备
- 为类变量(static)分配内存
- 赋默认值
static int a = 10;
准备阶段:
a = 0
1.4 解析
- 将符号引用 -> 直接引用
- 常量池中的类、方法、字段解析
1.5 初始化
- 执行方法
- static赋值 + static代码块
static {
a = 10;
}
真正的赋值发生在初始化阶段
2.双亲委派模型
2.1 类加载器
Bootstrap ClassLoader(核心类)
↓
Extension ClassLoader
↓
Application ClassLoader
↓
Custom ClassLoader
2.2 工作机制
先让父加载器尝试加载,父加载不了,子加载器才加载。
双亲委派是防止核心类被篡改,保证类唯一性(java.lang.String 永远唯一)
二、JVM内存模型(运行时数据区)
1.JVM内存整体结构
线程私有:
- 程序计数器
- 虚拟机栈
- 本地方法栈
线程共享:
- 堆
- 方法区(MetaSpace)
2.各区域深度剖析
2.1 程序计数器
- 当前线程执行字节码行号
- 唯一不会OOM的区域
2.2 虚拟机栈
(1)栈帧结构:
- 局部变量表
- 操作数栈
- 动态链接
- 返回地址
(2)异常:
- StackOverflowError(栈溢出错误)
- OutOfMemoryError(内存溢出错误)
2.3 堆
新生代:
Eden
S0
S1
老年代
2.4 方法区(MetaSpace)
- 类元信息
- 常量池
- 静态变量
JDK8后: 永久代 → MetaSpace(本地内存)
三、对象创建与内存分配机制
1.对象创建流程
1. 类是否加载
2. 分配内存
3. 设置对象头
4. 执行 <init>
2.对象内存结构
对象头:
- Mark Word
- Klass Pointer
实例数据
对齐填充
3.内存分配方式
(1)指针碰撞
- 堆内存连续
- Serial / ParNew
(2)空闲列表
- CMS
(3)TLAB
- 每个线程私有分配区
- 避免加锁
高并发对象创建必须靠TLAB
4.对象何时进入老年代
- 大对象(-XX:PretenureSizeThreshold)
- 长期存活(年龄阈值)
- Survivor空间不足
- 动态年龄判定
四、ParNew & CMS + 三色标记算法
1.三色标记算法
| 颜色 | 含义 |
|---|---|
| 白 | 未访问(垃圾候选) |
| 灰 | 已访问,子对象未扫描 |
| 白 | 已访问,子对象扫描完成 |
(1)并发问题
并发标记期间:黑对象 -> 新引用 -> 白对象(对象消失)
(2)解决方案:写屏障、增量更新 / satb
2.CMS收集器(老年代)
特点:
- 并发
- 低停顿
- 标记清除
流程:
初始标记(STW)
并发标记
重新标记(STW)
并发清除
缺点:
- 内存碎片
- 浮动垃圾
- CPU占用高
- Concurrent Mode Failure
五、G1&ZGC(现代JVM)
1.G1(JDK9默认)
(1)核心思想
- 堆划分为Region
- 不分新老代概率
- 按收益回收
(2)优势
- 可预测停顿
- 整理内存
- 大堆友好
(3)核心机制
- Remembered Set
- SATB
- Mixed GC
2.ZGC(JDK 11+)
(1)目标:停顿 < 10ms,堆TB级
(2)技术点:
- 染色指针(Colored Pointer)
- Load Barrier
- 并发压缩
(3)特点
- 停顿 -> 极低
- 吞吐 -> 一般
- 堆大小 -> 超大
- JDK -> 11+
更多推荐




所有评论(0)