• JVM学习笔记五:虚拟机类加载机制


    类加载生命周期

    类加载生命周期:加载、验证、准备、解析、初始化、使用、卸载
    jinjiprojectnaotu

    类加载或初始化过程什么时候开始?

    1. 遇到new、getstatic、putstatic或invokestatic这4条字节码指令时。
    2. 使用反射时,如果类没有初始化就触发其初始化
    3. 当初始化一个类时,如果其父类还没有初始化,则先初始化其父类
    4. 当虚拟机启动时,需要初始化主类。

    类加载阶段

    类加载的过程:

    1. 通过一个类的完全限定名获取定义此类的二进制字节流
    2. 将这个字节流所代表的静态存储结构转化为方法区的运行时数据结构
    3. 在内存中生成一个代表这个类的java.lang.Class对象,作为方法区这个类的访问入口

    验证阶段

    验证是链接的第一步,这一阶段的主要目标是为了确保Class文件的字节流中包含的信息符合当前虚拟机的要求。

    1. 文件格式验证
    2. 元数据验证
    3. 字节码验证

    Halting Problem 通过程序去校验程序逻辑是无法做到绝对准确的。

    为了优化验证效率,Code属性中增加了一项名为StackMapTable的属性,JDK1.6 虚拟机提供了 -XX:-UseSplitVerifier选项来关闭这项优化。

    4.符号引用验证

    准备阶段

    准备阶段是正式为类变量分配内存并设置初始值的阶段,注意这里的类变量非实例变量,初始值也仅仅是0值,或字段的属性表中存在ConstantValue,那么在准备阶段字段会被初始化为ConstantValue属性所指定的值。

    解析阶段

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

    什么时候发生解析呢? 答案是当用于操作符号引用的字节码被执行的时候,如new、getfield、invokevirtual

    符号引用解析的范围包括:类或接口、字段、类方法、接口方法、方法类型、方法句柄、调用点限定符

    初始化阶段

    初始化阶段是执行类构造器()方法的过程,() 方法是由编译器自动收集类中所有类变量的赋值动作和静态语句块中的语句合并而成。父类的()要先于子类执行。

    接口虽然没有静态代码块,但是编译器也会为其生成()方法,用于借口中定义的变量的初始化。

    虚拟机会保证一个类的()方法在多线程的环境中被正确的枷锁、同步,其他线程会阻塞,()方法只会被执行一次。

    类加载器

    每一个类加载器,都拥有一个独立的类名称空间,即使同样一个类被不同的两个类加载器加载,也被JVM认为是两个不同的类。

    双亲委派模型 Parents Delegation Model

    从JVM的角度讲只有两种类加载器,一种是启动类加载器(Bootstrap ClassLoader),一种是所有其他类加载器。

    从开发者的角度看,类加载器可以分为三种:

    1. 启动类加载器 Bootstrap ClassLoader,这个类加载器负责加载jdk/lib目录中的类,如rt.jar
    2. 扩展类加载器 Extension ClassLoader,这个加载器由sun.misc.Launcher$ExtClassLoader实现,他负责加载jdk/lib/ext目录中的类。
    3. 应用程序类加载器,这个加载器由sun.misc.Launcher$AppClassLoader实现,这个类加载器是ClassLoader.getSystemClassLoader()方法的实现,所以也称为系统类加载器,它负责加载用户类路径ClassPath上所指定的类库。

    下图展示的类加载器之间的关系,称为类加载器的双亲委派模型
    jinjiprojectnaotu2
    双亲委派模型的工作过程是:如果一个类加载器收到了类加载的请求,它首先不会自己去尝试加载这个类,而是把这个请求委托给父类加载器去完成,每一个层次的类加载器都是如此,因此所有的加载请求最终都应该传送到顶层的启动类加载器中,只有当父加载器反馈自己无法完成这个加载请求时,子加载器vaihui尝试自己去加载。

    实现一个满足双亲委派模型的类加载器只要继承ClassLoader,实现模型的方法都集中在loadClass中,只要自己实现findClass中自己查找的逻辑即可。

    破坏双亲委派模型,上一级的类加载器要访问下级类加载器加载的类时,可以通过线程上下文类加载器 Thread Context ClassLoader 这个类加载器可以通过Thread类setContextClassLoader()方法进行,这个值可以从父线程继承,如果没有进行设置默认就是应用程序类加载器。

    参考资料

    本文参考:《深入理解Java虚拟机》

  • 相关阅读:
    JPA总结——实体关系映射(一对多@OneToMany)
    JPA——映射持久化对象(Entity)
    jackson annotations注解详解
    Spring Data JPA
    Spring Data JPA初使用
    Spring注解Annotion详解
    JPA概要
    The requested resource is not available错误
    Servlet 工程 web.xml 中的 servlet 和 servlet-mapping 标签
    Spring——Eclipse上安装springsource-tool-suite与jar包详解
  • 原文地址:https://www.cnblogs.com/MinnieChang/p/7327962.html
Copyright © 2020-2023  润新知