JVM的类加载机制全面解析
什么是类加载机制
JVM把描述类的数据从Class文件加载到内存,并对数据进行校验、转换解析和初始化,最终形成可以被JVM直接使用的Java类型,这就是JVM的类加载机制。
如果你对Class文件的结构还不熟悉,可以参考之前的文章Class文件结构全面解析(上)和Class文件结构全面解析(下)。
欢迎关注微信公众号:万猫学社,每周一分享Java技术干货。
类的生命周期
类从被加载到内存中,到被卸载出内存,一共分为以下几步:
- 加载(Loading)
- 验证(Verification)
- 准备(Preparation)
- 解析(Resolution)
- 初始化(Initialization)
- 使用(Using)
- 卸载(Unloading)
类加载的全过程,包括其中的加载、验证、准备、解析、初始化几个阶段。
欢迎关注微信公众号:万猫学社,每周一分享Java技术干货。
加载
加载是类加载的第一阶段,在这一步中JVM规范要求完成了以下三件事:
- 通过一个类的全限定名来获取定义这个类的二进制字节流。
- 将这个字节流多代表的静态存储结构转化为方法区的运行时数据结构。
- 在内存中生成一个代表这个类的java.lang.Class对象。
以上要求其实并不具体,JVM的具体实现和应用都是比较灵活的。比如:获取这个类的二进制字节流,并没有说从哪获取,怎么获取,于是就有了从压缩包中读取(jar、war、ear)、从网络中获取(Applet)、运行时计算生成(动态代理)。对于不是数组的类的加载,我们可以定义自己的类加载器去控制字节流的获取方式。但是,对于数组类就不一样了,因为数组类本身不是通过类加载器创建的,而是JVM直接创建的。
欢迎关注微信公众号:万猫学社,每周一分享Java技术干货。
验证
这一阶段是为了保证Class文件的字节流中包含的信息符合当前JVM的要求,并且不危害JVM自身的安全。大致分为以下四个阶段:
文件格式验证
验证字节流是否符合Class文件格式的规范,能不能被当前JVM处理。验证点比较多,比如:是否以魔数0xCAFEBABE开头、主次版本号是否在当前JVM的处理范围内、常量池的常量是否有不被支持的常量类型、CONSTANT_Utf8_info类型的常量中是否有不符合UTF8编码的数据等等。这个阶段是基于二进制字节流进行验证的,只有这个阶段验证通过了,字节流才能进入内存的方法区储存。
欢迎关注微信公众号:万猫学社,每周一分享Java技术干货。
元数据验证
这个阶段主要是对类的元数据信息进行语义分析和校验,保证不存在不符合Java语言规范的元数据信息。比如:除了java.lang.Object以外的类是否有父类、是否继承了一个不允许被继承的类、非抽象类是否实现了其父类或接口中要求实现的所有方法、是否覆盖了父类的final字段等等。
欢迎关注微信公众号:万猫学社,每周一分享Java技术干货。
字节码校验
这个阶段通过数据流和控制流分析,确保程序语义是合法的、符合逻辑的。比如:放置和使用操作栈时数据类型保证一致、保证跳转指令不会跳转到方法体以外的字节码指令上、保证方法体中的类型转换是有效的等等。
欢迎关注微信公众号:万猫学社,每周一分享Java技术干货。
符号引用校验
这个阶段是对类自身以外(常量池中的各种符号引用)的信息进行匹配性校验,它发生在解析步骤中,确保解析能正常执行,比如:符号引用中通过字符串描述的全限定名是否能找到对应的类、符号引用中的类字段方法的访问性是否可以访问当前类等等。
欢迎关注微信公众号:万猫学社,每周一分享Java技术干货。
准备
在这个阶段里,为静态变量分配内存并设置静态变量初始值。这里说的初始值通常情况下,不是代码中写的初始值,而是数据类型的零值。代码中写的初始值,是在初始化阶段赋值的。如果是静态常量(被final修饰),这个阶段就会被直接赋值为代码中写的初始值。
欢迎关注微信公众号:万猫学社,每周一分享Java技术干货。
解析
在这个阶段里,JVM把常量池内的符号引用替换为直接引用。符号引用以一组符号来描述所引用的目标,符号可以是任何形式的字面量,只要使用时能无歧义地定位到目标即可,它和JVM实现的内存布局无关。直接引用可以是直接指向目标的指针、相对偏移量或是一个能间接定位到目标的句柄,它是和JVM实现的内存布局相关的。如果有了直接引用,那么引用的目标肯定在内存中存在。
解析主要针对类或接口、字段、类方法、接口方法、方法类型、方法句柄和调用点限定符的符号引用进行,分别对应常量池的CONSTANT_Class_info、CONSTANT_Fieldref_info、CONSTANT_Methodref_info、CONSTANT_InterfaceMethodref_info、CONSTANT_MethodType_info、CONSTANT_MethodHandle_info和CONSTANT_InvokeDynamic_info。
欢迎关注微信公众号:万猫学社,每周一分享Java技术干货。
初始化
初始化阶段才真正开始执行类中定义的字节码,也是执行类构造器()方法的过程。()方法是由编译器自动收集类中的所有静态变量的赋值动作和静态语句块中的语句合并产生的,编译器收集的顺序是用语句在源文件中出现的顺序所决定的,静态语句块只能访问到定义在静态语句块之前的变量,定义在它之后的变量,静态语句块可以赋值,但是不能访问。
JVM会保证在子类的()方法执行之前,父类的()方法已经执行完毕,也就是说父类中定义的静态语句块要优先于子类的变量赋值操作。如果类没有静态语句块,也没有对静态变量赋值,编译器就不会为这个类生成()方法。接口的()方法不需要先执行父接口的()方法,只有当父接口中定义的变量使用时,父接口才会被初始化。
JVM会保证一个类的()方法在多线程环境中被正确地加锁、同步。如果一个线程在执行这个类的()方法,其他线程都需要阻塞等待,当()方法执行完后,其他线程也不会再次进入()方法。同一个类加载器下,一个类只会被初始化一次。
欢迎关注微信公众号:万猫学社,每周一分享Java技术干货。
结语
这次我们了解了类加载过程的几个阶段,分别是加载、验证、准备、解析和初始化。加载是把二进制字节码载入内存,验证是校验字节流中包含的信息是否符合当要求,准备是为静态变量分配内存并设置静态变量初始值,解析是把常量池内的符号引用替换为直接引用,初始化是执行所有静态变量的赋值动作和静态语句块中的语句。
欢迎关注微信公众号:万猫学社,每周一分享Java技术干货。
JVM的类加载机制全面解析的更多相关文章
- 面试必问:JVM类加载机制详细解析
前言 在Java面试中,简历上有写JVM(Java虚拟机)相关的东西,JVM的类加载机制基本是面试必问的知识点. 类的加载和卸载 JVM是虚拟机的一种,它的指令集语言是字节码,字节码构成的文件是cla ...
- JVM内存结构 JVM的类加载机制
JVM内存结构: 1.java虚拟机栈:存放的是对象的引用(指针)和局部变量 2.程序计数器:每个线程都有一个程序计数器,跟踪代码运行到哪个位置了 3.堆:对象.数组 4.方法区:字节流(字节码文件) ...
- JVM之类加载机制
JVM之类加载机制 JVM类加载机制分为五个部分:加载,验证,准备,解析,初始化,下面我们就分别来看一下这五个过程. 类加载五部分 加载 加载是类加载过程中的一个阶段,这个阶段会在内存中生成一个代表这 ...
- 【转】JVM类装载机制的解析,热更新的探讨
引言 如有错误,请批评指正. Java是一种动态连接的语言.所谓动态连接,大概可以这么解释. 首先,Java可以大概想象成是编译解释执行的.对于一个*.java的文件,通过javac将会编译成一个*. ...
- 大白话谈JVM的类加载机制
前言 我们很多小伙伴平时都是做JAVA开发的,那么作为一名合格的工程师,你是否有仔细的思考过JVM的运行原理呢. 如果懂得了JVM的运行原理和内存模型,像是一些JVM调优.垃圾回收机制等等的问题我们才 ...
- 一文教你读懂JVM的类加载机制
Java运行程序又被称为WORA(Write Once Run Anywhere,在任何地方运行只需写入一次),意味着我们程序员小哥哥可以在任何一个系统上开发Java程序,但是却可以在所有系统上畅通运 ...
- JVM的类加载机制
虚拟机把描述类的数据从Class文件加载到内存,并对数据进行校验.转换解析和初始化,最终形成可以被虚拟机直接使用的Java类型,这就是虚拟机的类加载机制. 类加载的过程: 包括加载.链接(含验证.准备 ...
- 【JVM】类加载机制
原文:[深入Java虚拟机]之四:类加载机制 类从被加载到虚拟机内存中开始,到卸载出内存为止,它的整个生命周期包括:加载.验证.准备.解析.初始化.使用和卸载七个阶段.它们开始的顺序如下图所示: 类加 ...
- 深入理解JVM(3)——类加载机制
1.类加载时机 类的整个生命周期包括了:加载( Loading ).验证( Verification ).准备( Preparation ).解析( Resolution ).初始化( Initial ...
随机推荐
- NodeJs 实现 WebSocket 即时通讯(版本一)
服务端代码 var ws = require("nodejs-websocket"); console.log("开始建立连接...") var game1 = ...
- ubuntu 制作本地yum仓库
ubuntu 制作本地yum仓库 笔者: 张首富 W X: y18163201(请备注) qq群:895291458 时间:2019-01-31晚 今天到某银行进行软件部署的时候,碰到所有电脑都不允许 ...
- 【并发编程】Volatile原理和使用场景解析
目录 一个简单列子 Java内存模型 缓存不一致问题 并发编程中的"三性" 使用volatile来解决共享变量可见性 volatile和指令重排(有序性) volatile和原子性 ...
- 【java基础】接口是否能有实现类?
接口是否能有实现方法 我的回答: 当然可以 java8以后就允许接口有实现方法: default修饰的方法 static修饰的方法 /** * 能用lambda的情况,接口里面只有一个未实现的方法 * ...
- DB2中的MQT优化机制详解和实践
MQT :物化查询表.是以一次查询的结果为基础 定义创建的表(实表),以量取胜(特别是在百万,千万级别的量,效果更显著),可以更快的查询到我们需要的结果.MQT有两种类型,一种是系统维护的MQT , ...
- C语言I—2019秋作业01
1您对软件工程专业或计算机科学与技术专业了解是什么? 工程专业将成为一个新的热门专业.软件工程专业以计算机科学与技术学科为基础,突出软件开发的工程性,使学生在掌握计算机科学与技术方面知识和技能的基础上 ...
- NOI1995 石子合并 [Luogu P1880]
一道区间dp的模板题,这里主要记一下dp时环形数据的处理. 简略版:方法一:枚举分开的位置,将圈化为链,因此要做n次. 方法二:将链重复两次,即做一个2n-1长度的链,其中第i(i<=n)堆石子 ...
- EffectiveJava-2
一.使用类库 使用类库的好处: 无须关心方法是如何实现的,由算法专家花了大量时间设计.实现和测试这个方法,不仅保证了正确性,而且一旦有缺陷,下一个版本就会修复. 不必浪费时间为哪些与工作不太相关的问题 ...
- Eclipse SVN插件的帐号、密码修改
Eclipse的SVN插件Subclipse做得很好,在svn操作方面提供了很强大丰富的功能.但到目前为止,该插件对svn用户的概念极为淡薄,不但不能方便地切换用户,而且一旦用户的帐号.密码保存之后, ...
- php charles 使用方法
php charles 使用方法 打开charles 点击help菜单点击local ip address 可以获取本地ip 手机上选择代理这个ip 端口8888 然后手机访问网页 charles会弹 ...