类完整的生命周期包括加载,验证,准备,解析,初始化,使用,卸载,七个阶段.其中验证,准备,解析统称为连接,类的卸载在前面的关于垃圾回收的博文中已经介绍.

  加载,验证,准备,初始化,卸载这五个阶段的顺序是确定的,类的加载必须按照这种顺序按部就班的来,而解析阶段不一定,它可以在初始化阶段之后开始,这是为了支持java的运行时动态绑定.值得注意的是,上述的五个阶段只是按部就班的"开始",并不是按部就班的"进行"或者"完成",因为这些阶段通常是互相交叉混合进行的,通常会在一个阶段执行的过程调用,激活另一个阶段.

  在java虚拟机规范中并没有进行强制约束什么时候加载类,这是交给虚拟机具体实现自由把握,但是对于初始化阶段,虚拟机规范有严格规定:

  1.使用new实例化对象或者读取,设置一个类的静态字段(被final或者已在编译器吧结果放入常量池的静态字段除外)的时候以及调用一个类的静态方法的时候.

  2.使用反射调用的时候,如果类没初始化,需要进行初始化

  3,当初始化一个类的时候,父类没有初始化,则需要先初始化父类

  4.虚拟机启动时,用户需要制定一个执行类(包含main方法的那个类),虚拟机会先初始化这个主类.

  5.使用动态语言支持时,如果一个java.lang.MethodHandle实例最后解析结果REF_getStatic,REF_putStatic,REF_invokeStatic的方法句柄,并且这个句柄锁对应的类没有初始化,则初始化这个类.

  下面具体介绍类加载的过程.

1.加载

  加载阶段,虚拟机需要完成3件事情:

  1) 通过一个类的全限定名来获取定义此类的二进制字节流

  2) 将这个字节流锁代表的静态存储结构转化为方法区的运行时数据结构

  3) 在内存中生成带包这个类的Class对象,作为方法区这个类的各种数据访问入口.

  对于数组类而言,情况不同,数组类本身不通过类加载器创建,它是由java虚拟机直接创建.数组类的创建过程遵循以下规则:

  1) 如果数组的组件类型(指数组去掉一个维度的类型)是引用类,那就采取上述的方法来加载这个组件类型,数组C将在加载该组件类型的类加载器的类名空间上被标识

  2) 如果数组的组件类型不是引用类型(例如int[]),虚拟机会将数组标记为与引导类加载器关联

  3) 数组类的可见性与他的组件类型的可见性一直,如果组件类型不是引用类型,那数组类的可见性将默认为public.

  加载完成后,外部二进制字节流就按照虚拟机需要的格式存储在方法区中,然后实例化一个Class类的对象作为程序访问方法区中的这些类型数据的外部接口.

2.验证

  验证是连接的第一步,这一阶段为了确保Class文件的字节流中包含的信息符合当前虚拟机的要求,并且不会危害虚拟机自身的安全.验证分为四个阶段:文件格式验证,元数据验证,字节码验证,符号引用验证

  1) 文件格式验证是验证字节流是否符合Class文件格式的规范,并且能够被当前版本的处理机处理.

  2) 元数据验证是对字节码描述的信息进行语义分析,以保证其描述的信息符合java语言规范的要求.

  3) 字节码验证是只能怪过验证过程最复杂的阶段,主要是通过数流和控制流分析,确定程序语义是合法的,符合逻辑的.这个阶段对类的方法体进行校验分析,保证被校验类的方法在运行时不会出现危害虚拟机安全的事件.

  4) 符号引用验证发生在虚拟机将符号引用转化为直接引用的时候.这个动作是在解析阶段发生.

3.准备

  这个阶段是正式为类变量分配内存并设置类变量初始值的阶段,这些变量锁使用的内存都在方法区中分配.值得注意的是这里进行分配内存的仅包括类变量(被static修饰的变量),不包括实例变量,其次这里设置初始值是将值设为零值,例如一个整型类变量设置的零值是0,而不是代码中写出来的值.将代码写出来的值赋值给这个变量是初始化阶段做的事情

4.解析

  解析阶段是虚拟机将常量池的符号引用替换为直接引用的过程.解析包括类或接口的解析,字段解析,类方法解析,接口方法解析

5.初始化

  初始化是类加载的最后一步,在准备阶段,变量已经赋过一次系统要求的初始值,而在初始化阶段,则根据程序员通过程序制定的主观计划去初始化类变量和其他资源,或者换一种说法:初始化阶段是执行类构造器<clinit>()方法的过程.

  <cliinit>()方法时由编译器自动收集所有类变量的赋值动作和静态语句快中的语句合并产生的,收集的顺序是由语句在源文件中出现的顺序决定的,静态语句块只能访问到定义域在静态语句块之前的变量,后面的变量只能赋值,不能访问.

  <cliinit>()方法还有许多规定,请自行查找相关资料

6.类与类加载器

  类加载器虽然只用于实现类加载动作,但是在java程序中的还有其他作用.对于任意一个类加载器,都有一个独立的类名空间,而被这个类加载器加载出来的类,其类名会被标记上类加载器的类名空间,则两个特性决定了一个类在虚拟机中的唯一性.也就是说我们要比较两个类是否相等,前提是要这两个类是同一个类加载器加载出来的.否则就算是同一个class文件加载出来的这两个的也是不相等的.因为instanceof这个关键字会将两个类判定为不是同一个类,

7.双亲委派模型

  这个模型的工作过程是:如果一个类加载器收到了类加载请求,它首先不会自己尝试加载这个类,而是吧这个请求委派给父类加载器去完成.因此所有的加载请求最终都会送到顶层的启动类加载器,只有父类反馈无法完成类加载让子加载器才会尝试加载.这个模型使java的类不会因为类加载器不同而产生不同的相同类.

理解JVM之类加载机制的更多相关文章

  1. 深入理解JVM(3)——类加载机制

    1.类加载时机 类的整个生命周期包括了:加载( Loading ).验证( Verification ).准备( Preparation ).解析( Resolution ).初始化( Initial ...

  2. 深入理解JVM - 虚拟机类加载机制 - 第七章

    类加载的时机类从被加载到虚拟机内存开始,到卸载出内存为止,它的整个生命周期包括了:加载/验证/准备/解析/初始化/使用/卸载七个阶段.其中验证/准备和解析统称为连接(Linking). 加载.验证.准 ...

  3. 深入理解JVM的类加载

    前言: 前面又说到Java程序实际上是将.class文件放入JVM中运行.虚拟机把描述类的数据从Class文件加载到内存,并对数据进行校验,转换,解析和初始化,最终形成可以被虚拟机直接使用的Java类 ...

  4. 【深入理解JVM】类加载器与双亲委派模型 (转)

    出处: [深入理解JVM]类加载器与双亲委派模型 加载类的开放性 类加载器(ClassLoader)是Java语言的一项创新,也是Java流行的一个重要原因.在类加载的第一阶段“加载”过程中,需要通过 ...

  5. 大白话谈JVM的类加载机制

    前言 我们很多小伙伴平时都是做JAVA开发的,那么作为一名合格的工程师,你是否有仔细的思考过JVM的运行原理呢. 如果懂得了JVM的运行原理和内存模型,像是一些JVM调优.垃圾回收机制等等的问题我们才 ...

  6. 一文教你读懂JVM的类加载机制

    Java运行程序又被称为WORA(Write Once Run Anywhere,在任何地方运行只需写入一次),意味着我们程序员小哥哥可以在任何一个系统上开发Java程序,但是却可以在所有系统上畅通运 ...

  7. JVM内存结构 JVM的类加载机制

    JVM内存结构: 1.java虚拟机栈:存放的是对象的引用(指针)和局部变量 2.程序计数器:每个线程都有一个程序计数器,跟踪代码运行到哪个位置了 3.堆:对象.数组 4.方法区:字节流(字节码文件) ...

  8. JVM之类加载机制

    JVM之类加载机制 JVM类加载机制分为五个部分:加载,验证,准备,解析,初始化,下面我们就分别来看一下这五个过程. 类加载五部分 加载 加载是类加载过程中的一个阶段,这个阶段会在内存中生成一个代表这 ...

  9. JVM的类加载机制全面解析

    什么是类加载机制 JVM把描述类的数据从Class文件加载到内存,并对数据进行校验.转换解析和初始化,最终形成可以被JVM直接使用的Java类型,这就是JVM的类加载机制. 如果你对Class文件的结 ...

随机推荐

  1. 零基础学Python_汇总贴

    https://time.geekbang.org/course/intro/98 零基础学Python-第一章 :Python介绍和安装-01.Python语言的特点 零基础学Python-第一章 ...

  2. Python - Django - request 对象

    request.method: 获取请求的方法,例如 GET.POST 等 views.py: from django.shortcuts import render, HttpResponse # ...

  3. npm publish 一直报错 404

    在封装 zswui  react ui 组件库的时候,尝试了下 github的 packages 包设置,然后就给自己挖坑了. zswui   这是一个从零开始配置,实现组件开发测试的项目. 因为设置 ...

  4. 【ssh连接docker container问题】

    在向docker container执行ssh或scp的时候,应该将docker container的22端口映射出来,然后ssh/scp命令指定映射出来的端口

  5. elasticsearch关键词查询不分词

    $query = [ 'bool' => [ 'must' => [ 'match_phrase' => ['content' => $word] //$word词不被分词 ] ...

  6. php mkdir没有权限不能创建成功的问题

    php用mkdir创建目录时,必须保证要创建的目录的父级目录有用户权限才行, 比如当前执行脚本的用户是www用户,要创建的目录是/data/www/bbs/attach/2018 则/data/www ...

  7. MySQL中事务的隔离级别

    MySQl InnoDB存储引擎实现SQL标准的4种隔离级别(RU,RC,RR,serializable),用来限定事务内外的哪些改变时可见的,哪些时不可见的.低级别的隔离级一般支持更高的并发处理,并 ...

  8. jQuery 控制網頁捲軸移動 & Ignore link '#' method jump action

    $('a.gotoheader').click(function(){ // 讓捲軸移動到 0 的位置 $(); // ignore link "#" method return ...

  9. Node.js 服务端图片处理利器

    sharp 是 Node.js 平台上相当热门的一个图像处理库,其实际上是基于 C 语言编写 的 libvips 库封装而来,因此高性能也成了 sharp 的一大卖点.sharp 可以方便地实现常见的 ...

  10. PRECONDITION_FAILED - inequivalent arg 'type' for exchange 'exchange' in vhost '/': received 'direct

    最近在搞rabbitmq,把解决问题方法记下 问题1:PRECONDITION_FAILED - inequivalent arg 'type' for exchange 'exchange' in ...