虚拟机类加载的机制
虚拟机类加载的机制
laohng1995 发表于10个月前
虚拟机类加载的机制
  • 发表于 10个月前
  • 阅读 9
  • 收藏 0
  • 点赞 0
  • 评论 0

腾讯云 技术升级10大核心产品年终让利>>>   

 

   虚拟机把描述数据从Class文件加载到内存,并对数据进行校验,转换分析和初始化,最终形成可以被虚拟机直接使用的Java类型,这就是虚拟机类加载机制。

 1.类加载的时机

类加载的生命周期包括:加载,验证,准备,解析,初始化,使用,卸载。

第一个阶段:加载。  

在加载阶段,虚拟机需要完成三个步骤:

第一,通过一个类的全限定名来获取定义此类的二进制流。

第二,将这个字节流所代表的静态存储结构转移为方法区的运行时数据结构

第三,在内存中生成一个代表累的java.lang.Class对象做作文程序访问的入口。

注意:对于数组类型而言,它本身不通过类加载器创建,他是通过虚拟机直接创建,但是仍然和类加载器有着重要的联系,因为数组类型当中元素的创建需要通过类加载器加载。Class对象比较特殊,它他虽然是对象,但是他是存储在方法区

第二个阶段:验证

验证阶段的目的是为了确保Class文件的字节流包含的信息符合当前虚拟机的要求,并且不能伤害虚拟机。

验证的第一阶段为:文件格式的验证,主要用于验证魔术,主次版本号等等

验证的第二阶段:元数据验证:对字节码描述的信息进行语意分析,确保其符合Java虚拟机语言规范。

验证的第三阶段:字节码验证:主要是通过数据流和控制流分析,确定程序合法,合乎逻辑。

验证的第四阶段:符号引用验证。

第三阶段:准备

准备阶段正式为变量分配内存和赋予初始值阶段,这部分的是在方法区内完成。这里所指的变量是指类变量而不是实例变量。例子:

public static int value=123

对于这个赋值而言,准备阶段过后的初始值为0而不是123,因为这个时候Java虚拟机还没有执行任何一个方法,而把value赋值123的putstatic指令实在程序编译后,存放在类构造器<clinit>()方法中,所以在动作执行阶段才能执行赋值。

第四阶段:解析

1.类或接口解析

  1>如果不是一个数组类型,则通过类加载,验证。

  2>如果是数组类型,并且数组的元素是对象类型,也会按照第一点解析

  3>如果前面都没有发生异常,则要进行权限认证

2.字段解析

1)简单的名称进行匹配

2)如果在其中实现接口,会按照继承关系从下向上递归查找各个接口和父接口

3)如果不是Object类的话,将会按照继承关系从下向上递归搜索其父类

4)如果都失败,抛出NoSuchFieldError异常,如果发现没有访问权限,抛出ILLegalAccessError异常

3.类方法解析

4.接口方法解析

第四阶段:初始化

初始化阶段是执行类构造器<cinit>()方法的过程。

<cinit>(()方法使所有的类变量赋值动作和静态语句块顺序所决定的,静态语句块只能访问静态语句块的变量。

<cinit>(()不需父类构造器显示的调用,虚拟机会保证子类的<cinit>()方法执行前父类的<cinit>()方法已经执行。因此第一个被执行的父类是Object的<cinit>()

<cinit>()静态语句块的执行要优先于类变量见得赋值。

<cinit>()对于或者接口与来说不是必须的,如果没有静态代码块和赋值的话,就可以不用<cinit>()。

虚拟机会保证在多线程中<cinit>()被正确的枷锁,同步和执行。

对4种情况必须初始化:

 1.使用new关键字实例化对象的时候,读取或者设置一个类的静态字段的时候,以及调用一个静态类方法的时候。

2.调用reflect包的方法进行反射调用的时候

3.初始化的时候如果发现父类没有初始化的时候要先给父类进行初始化

4.当虚拟机启动的时候需要执行Main方法那个类

 

3种不能触动初始化

1.子类引用父类的静态字段

2.通过数组定义来引用类

3.引用静态的方法

 

介绍一个模型:双亲委派模型

对于Java虚拟机来说,只存在两种不同角度的类加载器:一种是用c++语言实现的,启动类加载器。另一种是用Java语言实现的所有其他的类加载器,独立于虚拟机外,并且继承抽象类ClassLoader。

 

图形:

(1).BootStrap ClassLoader:启动类加载器,负责加载存放在%JAVA_HOME%\lib目录中的,或者通被-Xbootclasspath参数所指定的路径中的,并且被java虚拟机识别的(仅按照文件名识别,如rt.jar,名字不符合的类库,即使放在指定路径中也不会被加载)类库到虚拟机的内存中,启动类加载器无法被java程序直接引用。

(2).Extension ClassLoader:扩展类加载器,由sun.misc.Launcher$ExtClassLoader实现,负责加载%JAVA_HOME%\lib\ext目录中的,或者被java.ext.dirs系统变量所指定的路径中的所有类库,开发者可以直接使用扩展类加载器。

(3).Application ClassLoader:应用程序类加载器,由sun.misc.Launcher$AppClassLoader实现,负责加载用户类路径classpath上所指定的类库,是类加载器ClassLoader中的getSystemClassLoader()方法的返回值,开发者可以直接使用应用程序类加载器,如果程序中没有自定义过类加载器,该加载器就是程序中默认的类加载器。

双亲委派模型的工作过程:如果一个类加载器收到加载请求,他首先不会自己尝试加载这个类,而是把它委派给父类加载去完成。每一个层次都会尝试加载都是如此

共有 人打赏支持
粉丝 11
博文 31
码字总数 26491
×
laohng1995
如果觉得我的文章对您有用,请随意打赏。您的支持将鼓励我继续创作!
* 金额(元)
¥1 ¥5 ¥10 ¥20 其他金额
打赏人
留言
* 支付类型
微信扫码支付
打赏金额:
已支付成功
打赏金额: