【个人学习||JVM】02JVM的内存区域&&类加载&&对象创建过程
内存区域
01已经讲过了,不做赘述。
JVM 的内存区域:
- 程序计数器:工序卡指针
- 虚拟机栈:当前工单现场
- 本地方法栈:外协工位
- 堆:大仓库
- 方法区:档案室
所以“内存区域”本质上就是:
JVM 把内存切成几块,每块负责不同工作。
为什么要分区?
因为程序运行时有不同类型的数据:
- 有的是当前方法临时用的
- 有的是对象
- 有的是类的说明书
- 有的是下一条要执行的位置
这些东西生命周期、大小、用途都不同,所以 JVM 要分开管理。
线程私有
- 程序计数器
- 虚拟机栈
- 本地方法栈
线程共享
- 堆
- 方法区
类加载机制
类加载机制 就是:
一个 Java 类,从磁盘上的 .class 文件,变成 JVM 里可以使用的类,到底经历了什么过程。
01已经学了“元空间放类信息”,也就是工厂建好了,需要开始运行,但是我怎么知道需要怎么工作?
这些类信息是怎么进去的?
这就是类加载机制。
- .class 文件 = 外面送来的产品图纸
- JVM = 工厂
- 类加载器 = 把图纸搬进工厂的人
- 元空间 = 档案室
- 类加载机制 = 图纸进厂、审核、入档、能正式使用的全过程
1.类加载大致分 5 步
最常见的说法是:
- 加载
- 验证
- 准备
- 解析
- 初始化
1. 加载
把图纸搬进厂里
把 .class 文件读进 JVM。
比如你写了:
User u = new User();
JVM 先得找到 User.class,把它读进来。
这一阶段主要做三件事:
- 通过类的全限定名找到 .class
- 读入二进制字节流
- 在方法区/元空间里生成这个类的运行时结构
2. 验证
审核图纸是不是伪造的、是不是乱写的
检查这个类文件靠不靠谱,会不会危害 JVM。
比如检查:
- 文件格式对不对
- 字节码是否合法
- 语义是否合理
3. 准备
预留静态档案(static )位置
给 类变量(static变量) 分配内存,并赋默认初始值。
比如:
class Demo { static int a = 10; }
在“准备”阶段,先做的不是立刻赋值 10,而是:
- 给 a 分配空间
- 先给默认值 0
准备阶段:static 变量先拿默认值,不是程序员写的值
4. 解析
把图纸上的“去 A 车间”换成具体门牌号
把常量池里的“符号引用”替换成“直接引用”。
比如类里写了:
- 调用哪个方法
- 用哪个类
- 访问哪个字段
一开始很多只是“名字”,解析阶段会把这些名字变成 JVM 真正能定位到的目标。
5. 初始化
图纸正式生效,工厂开始按这份规则运行
真正执行类里的静态赋值和静态代码块。
比如:
class Demo { static int a = 10; static { System.out.println("初始化 Demo"); } }
到了初始化阶段,才真正执行:
- a = 10
- static { ... }
2.一个最简单的例子
class Demo {
static int a = 10;
static {
System.out.println("Demo 初始化");
}
}
public class Test {
public static void main(String[] args) {
System.out.println(Demo.a);
}
}
执行时大致是:
- JVM 发现要用 Demo
- 加载 Demo.class
- 验证它是否合法
- 准备:给 a 分配空间,先设默认值 0
- 解析:处理符号引用
- 初始化:
- 执行 static int a = 10
- 执行 static { System.out.println("Demo 初始化"); }
- 最后输出 10
3.类加载器是什么
类不是 JVM 自己凭空拿进来的,要有人去“搬”。
这个“搬运工”就是 类加载器。
常见有 3 个:
-
Bootstrap ClassLoader
加载核心类库,比如 java.lang.String -
Extension / Platform ClassLoader
加载扩展类库 -
Application ClassLoader
加载你自己写的应用类
可以理解成:
- 启动类加载器:总厂官方搬运队
- 扩展类加载器:分厂公共搬运队
- 应用类加载器:你自己项目的搬运队
4.双亲委派是什么
新图纸先问总厂档案室有没有,能用总厂的就不用你自己乱造。
一个类加载器收到加载请求后,不会先自己干,而是先往上问父加载器。父加载器能加载,就让父加载器加载;父加载器不行,自己再加载。
为什么这么做?
主要两个目的:
- 避免重复加载
- 保证核心类库安全
比如你自己写一个:
package java.lang;
public class String {
}
按正常机制,它不会随便替换 JVM 自带的 String。
这就是双亲委派的重要意义。
对象创建过程
Product p = new Product();
从01可以知道new Product() 创建出来的,就是一个 对象,是在堆里面的。
而这个讲的就是其创建过程
对应过程:
- 检查 Product 类是否已加载
- 在堆里分配对象内存
- 实例字段先设默认值
- 写入对象头
- 执行构造方法
- 把引用赋给 p
这是java的对象,
- 先确认 Product (图纸)已经入档
- 仓库(堆)里腾一个位置
- 先放空白默认货物
- 贴上产品标签
- 按构造规则完成初始装配
- 把货位编号 p交给工人
设置对象头
JVM 还会给对象写一些额外信息,比如:
- 这个对象属于哪个类
- 哈希码相关信息
- 锁相关信息
这些放在对象头里。
你现在先把它理解成:
给货物贴上标签:这是谁家的、什么类型。
更多推荐


所有评论(0)