类加载

作者: Audience0 | 来源:发表于2020-01-30 20:12 被阅读0次
    image.png

    类加载子系统:
    在Java虚拟机中,负责查找并装载类的部分称为类加载子系统,类加载子系统用于定位和加载编译后的class文件


    类加载的生命周期:
    类从被加载到虚拟机内存中开始,到卸载出内存位置,她的整个生命周期包括:加载,验证,准备,解析,初始化,使用和卸载7个阶段


    image.png

    1.加载
    首先,加载是 类加载的一个阶段,注意不要混淆.
    在加载阶段,虚拟机需要完成以下3件事情
    1)通过一个类的全限定名来获取定义此类的二进制字节流
    此处并没有指定字节流的来源,所以,可以是从JAR,WAR或者从网络,运行时计算生成(动态代理)都可以
    2)将这个字节流所代表的静态存储结构化为方法区的运行时数据结构
    方法区:用于存储已被虚拟机加载的类信息,常量,静态变量
    3)在内存中生成一个代表这个类的java.lang.Class对象,作为方法区这个类的各种数据的访问入口

    2.验证
    验证是连接阶段的第一步,目的是为了确保Class文件字节流中包含的信息符合当前虚拟机的要求,并且不会危害虚拟机自身的安全.
    1)文件格式验证
    是否以魔数0xCAFEBABE开头
    主次版本号是否在当前虚拟机处理范围之内
    .....
    2)元数据验证
    对字节码描述信息进行语义分析即验证class文件的Java语法是否正确
    这个类是否有父类(除了Object,其他的类都有父类)
    这个类是否继承了不可以被继承的类(被final修饰的类)
    这个类如果不是抽象类,则是否实现了所有父类要求必须实现的方法
    类中的字段,方法是否与父类产生矛盾(例如覆盖了父类final修饰的字段)
    ......
    3)字节码验证
    保证方法体中类型转换是有效的,例如是否把一个类赋值给一个不相关的类型上
    ......
    4)符号引用验证
    符号引用中通过字符串描述的全限定名是否能找到对应的类
    符号引用中的类,字段,方法的访问性(public,private,protected,default)是否可以被当前类访问
    ......

    3.准备 --- 为类变量分配内存并初始化
    准备阶段是连接阶段的第二阶段,该阶段是正式为 类变量 分配内存并设置类变量初始值的阶段,这些变量所使用的内存都将在方法区中进行分配.
    需注意:
    1)此处的内存分配和初始化都是针对于类变量.
    2)此处所谓的初始化是初步的(通常情况),并非真正的初始化.
    例如
    public static int value = 123;
    经过准备阶段之后,value的初始值是0,而不是123.因为这时候尚未开始执行任何Java方法,而把value赋值为123的putstatic指定是程序被编译后,存放在类构造器<clinit>()方法之中,所以把value赋值为123是在初始化阶段才会执行的
    3)也有一些特殊情况,如果定义的是常量,如下, 则在准备阶段就会初始化为123
    public static final int value = 123;

    4.解析
    解析阶段是虚拟机将常量池内的符号替换为直接引用的过程

    直接引用:
    直接引用可以是直接指定目标的指针,相对偏移量或者是一个间接定位到目标的句柄.

    1)类或接口解析
    2)字段解析
    3)类方法解析
    4)接口方法解析

    5.初始化
    类初始化阶段是加载过程的最后一步.到了初始化阶段,才真正开始执行类中定义的Java程序代码
    在准备阶段,变量已经赋过一次系统要求的初始值,而在初始化阶段,则根据程序员通过程序制定的主观计划去初始化类变量和其他资源,或者可以从另外一个角度来表达:初始化阶段是执行类构造器方法的过程.


    类加载器

    通过一个类的全限定名来获取描述此类的二进制字节流;
    类加载器主要实现类的加载;

    image.png

    Bootstrap ClassLoader启动类加载器(C++ 实现,是虚拟机的一部分);
    Extension ClassLoader 扩展类加载器(Java 实现,独立于虚拟机外部且全继承自 java.lang.ClassLoader)
    Application ClassLoader 应用程序加载器(Java实现)
    Custom ClassLoader 自定义类加载器(java实现,用户自己定义的)
    除了顶层的启动类加载器之外,其他类加载器都有自己的父类加载器;

    双亲委派模型:
    如果一个类加载器收到类加载的请求,它首先不会自己去尝试加载这个类,而是把这个请求委派给父类加载器去完成,每一个层次的类加载器都是如此,因此所有的家在请求最终都传到顶层的启动类加载器中,只有当父加载器反馈自己无法完成这个加载请求时,子加载器才会去尝试自己去加载

    双亲委派的好处:
    Java类随着它的加载器一起具备了一种带有优先级层次关系.
    例如Java.lang.Object,它存放在rt.jar之中,无论哪一个类加载器要加载这个类,最终都是委派给最顶层的Bootsrap ClassLoader去加载.保证了Object这个类加载出来都是同一个类(类与类比较,是建立在同一个加载器的基础上的)

    相关文章

      网友评论

          本文标题:类加载

          本文链接:https://www.haomeiwen.com/subject/jimithtx.html