JVM的类加载器与类加载过程

JVM02-类加载器

类加载器的作用

类加载器负责加载Class文件,Class文件在文件开头有特定的文件标示,将Class文件字节码内容加载到内存中,并将这些内存转化成方法区中的运行时数据结构并且ClassLoader只负责Class文件的加载,至于它是否可以运行,则由Execution Engine决定
类加载器

类加载器的种类

类加载器的种类

  • 启动类加载器(BootStrap)是采用C++语言编写,是Java中原生代码实现的加载器,负责加载$JAVA_HOME中jre/lib/rt.jar里所有的class
  • 扩展类加载器(Extension)负责加载JRE的扩展目录,lib/ext或者由java.ext.dirs系统属性指定的目录中的JAR包的类。由Java语言实现,父类加载器为null。
  • 应用程序类加载器(AppClassLoader)也叫系统类加载器,主要负责JVM启动时加载Classpath目录下的jar包和类,由Java语言实现,父类加载器为ExtClassLoader。
  • 用户类加载器,也就是用户自定义的加载器,用来自定义某些指定的类的加载。

双亲委派机制

  • 双亲委派机制:
      当一个类收到了类加载请求时,他首先不会自己去加载这个类,而是把这个请求委派给父类去完成,父类也是如此,因此所有的加载请求都会传送到启动类加载器,这是如果父类无法加载完成这个请求时,才会交给子类加载器进行加载。
  • 好处:
      这样每一个类的加载最终都会委托给顶层的启动类加载器进行加载,保证使用不同的类加载器进行加载时,每次加载出来的对象是同样的,同时也保证了本地类库不会被污染。
    双亲委派机制

类加载器的执行过程

  类加载器加载Class大致要经过如下8个步骤:

  1. 检测此Class是否载入过,即在缓冲区中是否有此Class,如果有直接返回对应的Class对象,否则进入步骤2;
  2. 如果没有父类加载器,则要么父类是根类加载器,要么本身就是根类加载器,则跳到第4步,如果父类加载器存在,则进入第3步。
  3. 依次使用根加载器,拓展类加载器,等其父类加载器去载入目标类,如果载入成功则跳至第8步,否则接着执行第5步。
  4. 请求使用根类加载器去载入目标类,如果载入成功则跳至第8步,否则跳至第7步。
  5. 当前类加载器尝试寻找Class文件,如果找到则执行第6步,如果找不到则执行第7步。
  6. 从文件中载入Class,成功则
  7. 抛出ClassNotFountException异常。
  8. 返回对应的java.lang.Class对象。

类加载的过程

  当程序主动使用某个类时,如果该类还未被加载到内存中,则JVM会通过加载、连接、初始化3个步骤来对该类进行初始化。如果没有意外,JVM将会连续完成3个步骤,所以有时也把这个3个步骤统称为类加载或类初始化。
类的加载过程

1.加载

  根据查找路径找到相应的class文件,然后读入到内存中去创建对象。类的加载方式分为:隐式加载和显示加载两种。

  • 隐式加载指的是程序在使用new关键词创建对象时,会隐式的调用类的加载器把对应的类加载到jvm中。
  • 显示加载指的是通过直接调用class.forName()方法来把所需的类加载到jvm中。

  类的加载由类加载器完成,类加载器通常由JVM提供,这些类加载器也是前面所有程序运行的基础,JVM提供的这些类加载器通常被称为系统类加载器。除此之外,开发者可以通过继承ClassLoader基类来创建自己的类加载器。

  类加载器通常无须等到“首次使用”该类时才加载该类,Java虚拟机规范允许系统预先加载某些类。

2.链接

当类被加载之后,系统为之生成一个对应的Class对象,接着将会进入连接阶段,连接阶段负责把类的二进制数据合并到JRE中。类连接又可分为如下3个阶段。

  • 1)检查:检查夹加载的class文件的正确性。

      验证阶段用于检验被加载的类是否有正确的内部结构,并和其他类协调一致,确保Class文件的字节流中包含信息符合当前虚拟机要求,不会危害虚拟机自身安全。验证阶段是Java非常重要的一个阶段,它会直接的保证应用是否会被恶意入侵的一道重要的防线,越是严谨的验证机制越安全。
    在该阶段主要完成以下四种验证:

    • 文件格式验证:验证字节流是否符合 Class 文件的规范。
    • 元数据验证:对字节码描述的信息进行语义分析。
    • 字节码验证:是整个验证过程中最复杂的一个阶段,通过验证数据流和控制流的分析,确定程序语义是否正确,主要针对方法体的验证.
    • 符号引用验证:这个动作在后面的解析过程中发生,主要是为了确保解析动作能正确执行。
  • 2)准备:给类中的静态变量分配内存空间,并设默认初始值。

  • 3)解析:虚拟机将常量池中的符号引用替换成直接引用的过程。符号引用就理解为一个标示,而在直接引用直接指向内存中的地址。解析动作并不一 定在初始化动作完成之前,也有可能在初始化之后。

3.初始化

  执行静态变量和静态代码块。准备阶段和初始化阶段看似有点矛盾,其实是不矛盾的,如果类中有语句:private static int a = 10,它的执行过程是这样的,首先字节码文件被加载到内存后,先进行链接的验证这一步骤,验证通过后准备阶段,给a分配内存,因为变量a是static的,所以此时a等于int类型的默认初始值0,即a=0,然后解析,到初始化这一步骤时,才把a的真正的值10赋给a,此时a=10。

参考

https://blog.csdn.net/m0_38075425/article/details/81627349?utm_source=blogxgwz4

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值