一、类加载机制(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+
Logo

汇聚全球AI编程工具,助力开发者即刻编程。

更多推荐