一、类的生命周期
- 使用类时,要先使用类加载器将类的字节码从磁盘加载到内存的方法区中,用Class对象表示加载到内存中的类,Class类是JDK中提供的类
- 创建对象时,是根据内存中的Class对象,在堆中分配内存,完成对象的创建
类的生命周期是指类从被加载到虚拟机内存中开始到卸载出内存为止,它的整个生
命周期可以简单概括为 7 个阶段:
- 加载(Loading)
- 验证(Verification)
- 准备(Preparation)
- 解析(Resolution)
- 初始化(Initialization)
- 使用(Using)
- 卸载(Unloading)
其中,验证、准备和解析这三个阶段可以统称为连接(Linking)。
注意:
- 加载类(Loading)是由 类加载器 实现加载的
- 类加载后在内存中产生一个 Class对象 ,来表示被加载类的元数据
- 一个类在内存中 只加载一次 ,因此一个类只有一个Class对象
- 加载阶段:将字节码加载到内存
- 验证阶段:验证代码是否符合虚拟机规范,保证代码运行后不会危害虚拟机自身的
安全 - 准备阶段:正式为类变量分配内存并设置类变量初始值的阶段
- 解析阶段:虚拟机将常量池内的符号引用替换为直接引用的过程
- 初始化阶段:执行初始化是类加载的最后一步,这一步 JVM 才开始真正执行类中定
义的 Java 程序代码 - 卸载阶段:卸载阶段是类的 Class 对象被从内存中回收,释放内存
二、对象的创建过程
-
Step1:类加载检查
虚拟机遇到一条 new 指令时,首先检测类是否已被加载过、解析和初始化过。如果没有,那必须先执行相应的类加载过程。
-
Step2:分配内存
在类加载检查通过后,接下来虚拟机将为新生对象分配内存。对象所需的内存大小在类加载完成后便可确定,为对象分配空间的任务等同于把一块确定大小的内存从 Java 堆中划分出来。分配方式有 “指针碰撞” 和 “空闲列表” 两种,选择哪种分配方式由 Java 堆是否规整决定,而 Java 堆是否规整又由所采用的垃圾收集器是否带有压缩整理功能决定。
- 指针碰撞
- 适用场合:堆内存规整(即没有内存碎片)的情况下。
- 原理:用过的内存全部整合到一边,没有用过的内存放在另一边,中间有一个分界指针,只需要向着没用过的内存方向将该指针移动对象内存大小位置即可。
- 空闲列表
- 适用场合:堆内存不规整的情况下。
- 原理:虚拟机会维护一个列表,该列表中会记录哪些内存块是可用的,在分配的时候,找一块儿足够大的内存块儿来划分给对象实例,最后更新列表记录。
- 指针碰撞
-
Step3:初始化零值
内存分配完成后,虚拟机需要将分配到的内存空间都初始化为零值,这一步操
作保证了对象的实例字段在 Java 代码中可以不赋初始值就直接使用,程序能访
问到这些字段的数据类型所对应的零值。 -
Step4:设置对象头(了解即可)
初始化零值完成之后,虚拟机要对对象进行必要的设置,例如这个对象是哪个
类的实例、如何才能找到类的元数据信息、对象的哈希码、对象的 GC 分代年龄
等信息。 这些信息存放在对象头中。 另外,根据虚拟机当前运行状态的不同,
如是否启用偏向锁等,对象头会有不同的设置方式。 -
Step5:执行 init 方法
在上面工作都完成之后,从虚拟机的视角来看,一个新的对象已经产生了,但
从 Java 程序的视角来看,对象创建才刚开始, 方法还没有执行,所有
的字段都还为零。所以一般来说,执行 new 指令之后会接着执行 方
法,把对象按照程序员的意愿进行初始化,这样一个真正可用的对象才算完全
产生出来。
对象的创建过程就是类的声明周期中的 使用 阶段