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

  加载,验证,准备,初始化,卸载这五个阶段的顺序是确定的,类的加载必须按照这种顺序按部就班的来,而解析阶段不一定,它可以在初始化阶段之后开始,这是为了支持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. 记一次haproxy反向代理配置

    首先借用一下前辈的话,解释下反向代理是什么? 反向代理:以代理服务器来接受internet上的连接请求,然后将请求转发给内部网络上的服务器,并将从服务器上得到的结果返回给internet上请求连接的客 ...

  2. k8s-基础环境配置(六)

    hostname配置1)修改主机名hostnamectl set-hostname xxx2)加入主机映射vim /etc/hosts……关闭selinuxsed -i '/^SELINUX/s/=. ...

  3. vs2010 出错:error LNK1123: 转换到 COFF 期间失败: 文件无效或损坏(转)

    “LNK1123:转换到 COFF期间失败:文件无效或损坏”的解决方法 一.错误描述 之前写的程序隔段时间使用VS2010再次运行时出现如下错误: LINK fatal error LNK1123转换 ...

  4. linux 下修改时间

    修改linux的时间可以使用date指令 date命令的功能是显示和设置系统日期和时间. 输入date 查看目前系统时间. 修改时间需要 date -功能字符 修改内容 命令中各选项的含义分别为: - ...

  5. 微信小程序中的事件绑定

    前言: 微信小程序中的事件绑定和Vue中的事件绑定其实有很多的相似之处,所以如果有过Vue相关的经验,学起来的话还是比较容易的. js代码: // 页面级的js文件必须调用Page函数来注册页面, / ...

  6. Haproxy+keepalived高可用集群实战

    1.1  Haproxy+keepalived高可用集群实战 随着互联网火热的发展,开源负载均衡器的大量的应用,企业主流软件负载均衡如LVS.Haproxy.Nginx等,各方面性能不亚于硬件负载均衡 ...

  7. mysql 库、表、数据的增删改

    数据库定义 语法形式 (1)创建数据库 create database [if not exists ] 数据库名 [charset 字符集] [collate 字符排序规则]; if not exi ...

  8. [学习笔记] 下载、安装、启动 Eclipse(OEPE)

    OEPE 的全称是: Oracle Enterprise Pack for Eclipse 截止目前的最新版本是:(12.2.1.9) 下载地址:(需要在甲骨文官网注册一个账户才能下载) https: ...

  9. linux编程 新建一个进程的方法

    学习到一种,直接调用系统函数,在类的构造函数中直接启动一个线程,例如,某个类是用来监听串口的,可以直接在其构造函数中调用系统函数,开辟一个进程,在该进程对应的函数中不断while(1){....} h ...

  10. log4j向指定文件输出日志

    一.log4j.properties中的配置 log4j.logger.cache=INFO,ERROR,batchFile log4j.addivity.batchFile=false log4j. ...