jvm类加载机制

jvm类加载机制

所谓类加载机制实质我们将类的字节码文件包含的数据读入内存,同时,我们会生成数据访问入口的特殊机制。

 

由图所知,类加载机制最终产生的是数据访问入口。

字节码加载的方式

字节码加载的方式分为以下几种

  • 从本地系统加载

  • 从网络下载.class文件加载

  • 从zip,rar等中加载

  • 从数据库中获得特有.class文件加载

  • java源码编译成.class文件

  • 从加密文件中获取

类加载流程

 

即所谓类加载机制就是虚拟机把Class文件加载到内存,并对数据进行校验,转换解析和初始化,形成可以虚拟机直接使用的Java类型,即java.lang.Class

3.1 首先是装载

(1)通过一个类的全限定名获取定义此类的二进制字节流

(2)将这个字节流所代表的静态存储结构转化为方法区的运行时数据结构

(3)在Java堆中生成一个代表这个类的java.lang.Class对象,作为对方法区中这些数据的访问入口

装载完成后,此时在我们的方法区和堆中就有数据了。

  • 方法区:类信息 静态变量 常量

  • 堆:存储被加载的类的对象

3.2 链接

3.2.1 验证

验证只要是为了确保Class文件中的字节流包含的信息完全符合当前虚拟机的要求,并且还要求我们的信息不会危害虚拟机自身的安全,导致虚拟机的崩溃。 文件格式验证 验证字节流是否符合Class文件格式的规范,并且能被当前版本的虚拟机处理,该验证的主要目的是保证输入的字节流能正确地解析并存储于方法区之内。这阶段的验证是基于二进制字节流进行的,只有经过该阶段的验证后,字节流才会进入内存的方法区中进行存储,后面验证都是基于方法区的存储结构进行的。 举例: 1.是否以16进制cafebaby开头 2.版本号是否正确 元数据验证 对类的元数据信息进行语义校验(其实就是对Java语法校验),保证不存在不符合Java语法规范的元数据信息。 举例: 1.是否有父类 2.是否继承了final类 因为我们的fifinal类是不能被继承的,继承了就会出现问题。 3.一个非抽象类是否实现了所有的抽象方法 如果没有实现,那么这个类也是无效的。 总结:对类的元数据信息进行语义校验(其实就是对Java语法校验),保证不存在不符合Java 语法规范的元数据信息。 字节码验证 进行数据流和控制流分析,确定程序语义是合法的、符合逻辑的。对类的方法体进行校验分析,保证被校验的类的方法在运行时不会做出危害虚拟机安全的行为。获取类的二进制字节流的阶段是我们JAVA程序员最关注的阶段,也是操控性最强的一个阶段。因为这个阶段我们可以对于我们的类加载器进行操作,比如我们想自定义类加载器进行操作用以完成加载,又或者我们想通过JAVA Agent来完成我们的字节码增强操作。 举例: 字节码的验证会相对来说较为复杂 。 1.运行检查 2.栈数据类型和操作码操作参数吻合(比如栈空间只有4个字节,但是我们实际需要的远远大于4个字节,那么这个时候这个字节码就是有问题的) 3.跳转指令指向合理的位置 符号引用验证 这是最后一个阶段的验证,它发生在虚拟机将符号引用转化为直接引用的时候(解析阶段),可以看作是对类自身以外的信息(常量池中的各种符号引用)进行匹配性的校验。符号引用验证的目的是确保解析动作能正常执行。 举例: 1.常量池中描述类是否存在 2.访问的方法或者字段是否存在且具有足够的权限 注意:但是,我们很多情况下可能认为我们的代码肯定是没问题的,验证的过程完全没必要,那么其 实我们可以添加参数-Xverify:none 取消验证。

3.2.2 准备

为类的静态变量分配内存,并将其初始化为默认值

3.2.3 解析

解析阶段是虚拟机将常量池内的符号引用替换为直接引用的过程。解析动作主要针对类或接口、字段、类方法、接口方法、方法类型、方法句柄和调用限定符7类符号引用进行。

3.3 初始化

初始化阶段是执行类构造器()方法的过程。 或者讲得通俗易懂些 在准备阶段,类变量已赋过一次系统要求的初始值,而在初始化阶段,则是根据程序员通过程序制定的主观计划去初始化类变量和其他资源,比如赋值。在Java中对类变量进行初始值设定有两种方式:

  • 声明类变量是指定初始值

  • 使用静态代码块为类变量指定初始值 按照程序员的逻辑,你必须把静态变量定义在静态代码块的前面。因为两个的执行是会根据代码编写 的顺序来决定的,顺序搞错了可能会影响你的业务代码。 JVM初始化步骤:

  • 假如这个类还没有被加载和连接,则程序先加载并链接该类

  • 假如该类的直接父类还没有被初始化,则先初始化其直接父类

  • 假如类中有初始化语句,则系统依次执行这些初始化语句

3.4 使用

主动引用 只有当对类的主动使用的时候才会导致类的初始化,类的主动使用有六种:

  • 创建类的实例,也就是new的方式

  • 访问某个类或接口的静态变量,或者对该静态变量赋值

  • 调用类的静态方法

  • 反射(如 Class.forName(“com.carl.Test”) )

  • 初始化某个类的子类,则其父类也会被初始化

  • Java虚拟机启动时被标明为启动类的类(JvmCaseApplication ),直接使用 java.exe 命令来运行某个主类

    被动引用 引用父类的静态字段,只会引起父类的初始化,而不会引起子类的初始化。 定义类数组,不会引起类的初始化。 引用类的static final常量,不会引起类的初始化(如果只有static修饰,还是会引起该类初始化的)。

3.5 卸载

在类使用完之后,如果满足下面的情况,类就会被卸载:

  • 该类所有的实例都已经被回收,也就是java堆中不存在该类的任何实例。 加载该类的ClassLoader已经被回收。

  • 该类对应的java.lang.Class对象没有任何地方被引用,无法在任何地方通过反射访问该类的方 法。

  • Java虚拟机本身会始终引用这些类加载器,而这些类加载器则会始终引用它们所加载的类的 Class对象,因此这些Class对象始终是可触及的。 如果以上三个条件全部满足,jvm就会在方法区垃圾回收的时候对类进行卸载,类的卸载过程其实就 是在方法区中清空类信息,java类的整个生命周期就结束了。但是一般情况下启动类加载器加载的类 不会被卸载,而我们的其他两种基础类型的类加载器只有在极少数情况下才会被卸载

以上为课上笔记

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值