JVM虚拟机-类加载

  1. 加载机制:
    JVM把描述类的数据从Class文件加载到内存,并对数据进行校验,转换解析和初始化,最终形成可以被JVM直接使用的java类型。
    2.类的生命周期
    类从被加载到jvm内存中开始,到卸载出内存为止,生命周期包括:
    加载(loading)
    验证(Verification)
    准备(Preparation)
    解析(Resolution)
    初始化(Initialization)
    使用(Using)
    卸载(Unloading)
    JVM虚拟机-类加载_第1张图片
    3.类的初始化:
    主动引用:
    a.遇到new,getstatic,putstatic或invokestatic这些字节码指令时,如果类没有进行初始化,则需要先触发其初始化.
    场景:
    1)使用new关键字实例化对象,
    2)读取或设置一个类的静态字段(final修饰,已在编译期把结果放入常量池的静态字段,这种情况除外),
    3)调用一个类的静态方法
    b.使用java.lang.reflect包的方法对类进行反射调用,需要先对类进行初始化
    c.初始化一个类时,如果父类没有进行过初始化,需要先对父类进行初始化
    d.JVM启动时,用户需要指定一个要执行的主类(包含main方法的类),jvm需要先初始化该类
    e.JDK1.7的动态语言,如果一个java.lang.invoke.MethodHandle实例最后的解析结果是REF_getStatic,REF_putStatic,REF_invokeStatic的方法句柄,这个方法句柄对应的类没有进行过初始化
    被动引用:不会触发类的初始化
    a.通过子类引用父类的静态字段,不会导致子类初始化
    b.通过数组定义来引用类,不会触发此类的初始化
    c.常量在编译阶段会存入调用类的常量池中,本质上并没有直接引用到定义常量的类,因此不会触发定义常量的类的初始化
    3.接口的初始化:
    与类初始化的区别:当一个类在初始化时,要求其父类全部都已经初始化过了,但是一个接口在初始化时,并不要求其父类接口全部都完成了初始化,只有在真正使用到父接口时(如引用接口中定义的常量)才会初始化
    4.类加载的过程:加载,验证,准备,解析,初始化
    <1>加载
    a.需要做的事情
    1)通过一个类的全限定名来获取定义此类的二进制字节流
    2)将字节流所代表的静态存储结构转化为方法区的运行时数据结构
    3)在内存中生成一个代表这个类的java.lang.Class对象,作为方法区这个类的各种数据访问入口
    b.类加载:
    既可以使用系统提供的引导类加载器来完成,也可以由用户自定义的类加载器完成
    c.数组加载:
    1)数组的组件类型是引用类型,递归采用类加载过程加载组件类型,数组将在加载组件类型的类加载器的类名称空间上被标识
    2)数组的组件类型不是引用类型,JVM将会把数组标记为与引导类加载器关联
    3)数组类的可见性与组件类型的可见型一致,组件类型不是引用类型,数组类可见性默认为public
    <2>验证:重要但非必要(使用-Xverify:none关闭大部分类验证措施)
    a.需要做的事情:
    1) 文件格式验证:(利用class的组成规范)
    基于二进制字节流验证是否符合Class文件格式规范,并且能被当前版本的jvm处理
    2)元数据证:(利用java语言规范)
    对字节码描述的信息进行语义分析,保证其描述的信息符合Java语言规范的要求
    3)字节码验证:
    对类的方法体进行校验分析,保证类的方法在运行时不会做出危害JVM安全的事件
    4)符号引用验证:
    对类自身以外(常量池中的各种符号引用)进行匹配性校验,确保解析动作能正常执行,无法通过验证时会抛出java.lang.IncompatibleClassChangeError异常的子类,如java.lang.IllegalAccessError,java.lang.NoSuchFieldError,java.lang.NoSuchMethodError
    <3>准备:
    a.需要做的事情:
    正式为类变量分配内存并设置类变量初始值
    b.备注:
    1)进行内存分配仅包括类变量(被static修饰的变量),而不包括实例变量,实例变量将会对象实例化时随着对象一起分配在java堆中
    2)如果类的字段属性表中存在ConstantValue属性,在准备阶段变量value会被初始化为ConstantValue属性所指定的值(类变量被final修饰时,编译时Javac会为该变量生成ConstantValue属性)
    c.基本数据类型的零值
    JVM虚拟机-类加载_第2张图片
    <4>解析:
    a. 需要做的事情:
    JVM将常量池内的符号引用替换为直接引用过程,解析动作主要针对类或接口,字段,类方法,接口方法,方法类型,方法句柄和调用点限定符7类符号引用进行,分别对应于常量池的CONSTANT_Class_info,CONSTANT_Fieldref_info,CONSTANT_Methodref_info,CONSTANT_InterfaceMethodref_info,CONSTANT_MethodType_info,CONSTANT_MethodHandle_info,CONSTANT_InvokeDynamic_info
    b.符号引用和直接引用
    1)符号引用:以一组符号来描述所引用的目标,可以是任何形式的字面量,其形式明确定义在java虚拟机规范的Class文件格式中
    2)直接引用:可以是直接指向目标的指针,相对偏移量或是一个能间接定位到目标的句柄.如果有了直接引用,引用的目标必须保证在内存中存在
    c.类或接口的解析:
    假设:代码所处的类为D,要把一个从未解析过的符号引用N解析为一个类或接口C的直接引用
    1)如果C不是一个数组类型,JVM会把代表N的全限定名传递给D的类加载去加载类C
    2)如果C是一个数组类型,数组的元素类型为对象,会按照上面1)的规则加载数组元素类型,数组的元素类型为基本类型,JVM会生成一个代表此数组维度和元素的数组对象
    3)如果1)和2)没有异常,C在JVM中成为一个有效的类或接口,在解析完成之前进行符号引用验证,确认D是否具备对C的访问权限
    d.字段解析:
    解析一个未被解析字段的符号引用,首先会对字段表内的CONSTANT_Class_info符号引用进行解析,解析成功后字段所属的类或接器口用C表示,按如下步骤进行后续字段搜索
    1)C本身包含了简单名称和字段描述符与目标匹配字段,返回字段直接引用
    2)如果C中实现了接口,将按照继承关系从下往上递归搜索各个接口和父接口,接口中包含了简单名称和字段描述都与目标相匹配的字段,返回字段的直接引用
    3)如果C不是java.lang.Object,按照继承关系从下往上递归搜索父类,父类包含字段则返回
    4)否则,查找失败,抛出java.lang.NoSuchFieldError异常
    备注:如果一个同名字段同时出现在C的接口和父类中,或者同时在自己或父类的多个接口中出现,则会编译不通过
    e.类方法解析:
    1)类方法和接口方法引用的常量类型定义是分开,如果类方法的class_index中索引的C是个接口,则抛出异常
    2)在类C中查找有简单名称和描述符与目标匹配的方法,返回方法直接引用
    3)递归查找父类返回引用
    4)递归查找接口列表及它们的父接口,如果存在匹配方法,说明类C是abstract,查找结束,抛出java.lang.AbstractMethodError异常
    5)否则抛异常java.lang.NoSuchMethodError
    f.接口方法解析(同上在所有接口和父接口递归查找)
    <5>初始化
    类的初始化是类加载过程的最后一步,此阶段根据程序员通过程序制定主观计划去初始化类变量和其他资源。从另一个角度来讲:初始化阶段是执行类构造器()方法的过程。
    clinit方法:是由编译器自动收集类中的所有类变量的赋值动作和静态语句块(static块)合并产生(编译器收集的顺序是由语句在源文件中出现的顺序所决定的,静态语句块只能访问到定义在静态语句块之前的变量,定义其之后的变量,在前面的静态语句块可以赋值,但是不能访问)
    注意:
    a.方法不需要显式调用父类构造器,jvm保证子类方法执行之前,父类的()方法已经执行完毕.jvm第一个被执行的方法的类肯定是java.lang.Object
    b.父类的方法先执行,意味父类中定义的静态语句块优先于子类的变量赋值操作
    c.方法对于类或接口是非必需的,类中没有静态语句块,没有对变量的赋值操作,编译器可以不为此类生成方法
    d.接口的方法不需要先执行父接口的方法,只有当父接口中定义的变量使用时,父接口才会初始化,接口实现类也不会执行接口的方法
    e.jvm保证一个类的方法在多线程环境中被正确地加锁,同步,多线程初始化一个灰,只会有一个线程执行类的方法,其他线程阻塞,其他线程被唤醒之后不会再次进入方法,同一个类加载器,一个类型只会初始化一次

你可能感兴趣的:(虚拟机,虚拟机)