简介

有了java class文件之后,为了让class文件转换成为JVM可以真正运行的结构,需要经历加载,链接和初始化的过程。

这三个过程是怎么工作的呢?在本文中你将会找到答案。

加载

JVM可以分为三大部分,五大空间和三大引擎,要讲起来也不是特别复杂,先看下面的总体的JVM架构图。

从上面的图中,我们可以看到JVM中有三大部分,分别是类加载系统,运行时数据区域和Execution Engine。

加载就是根据特定名称查找类或者接口的二进制表示,并根据此二进制表示来创建类和接口的过程。

运行时常量池

我们知道JVM中有一个方法区的区域,在JDK8中,方法区的实现叫做元空间。这个元空间是存放在本地内存中的。

方法区中存放着每个class对应的运行时常量池。

当类或者接口创建的时候,就会通过class文件中定义的常量池来构建运行时常量池。

运行时常量池中有两种类型,分别是symbolic references符号引用和static constants静态常量。

其中静态常量不需要后续解析,而符号引用需要进一步进行解析处理。

静态常量分为两个部分:String常量和数字常量。

String常量是对String对象的引用,是从class中的CONSTANT_String_info结构体构建的。

数字常量是从class文件中的CONSTANT_Integer_info, CONSTANT_Float_info, CONSTANT_Long_info和 CONSTANT_Double_info 构建的。

符号引用也是从class中的constant_pool中构建的。

对class和interface的符号引用来自于CONSTANT_Class_info。

对class和interface中字段的引用来自于CONSTANT_Fieldref_info。

class中方法的引用来自于CONSTANT_Methodref_info。

interface中方法的引用来自于CONSTANT_InterfaceMethodref_info。

对方法句柄的引用来自于CONSTANT_MethodHandle_info。

对方法类型的引用来自于CONSTANT_MethodType_info。

对动态计算常量的符号引用来自于CONSTANT_MethodType_info。

对动态计算的call site的引用来自于CONSTANT_InvokeDynamic_info。

类加载器

类是怎么创建的呢?类的创建可以是由其他类调用该类的初始化方法来创建,也可以通过反射来创建。

类其实又可以分为两种,一种是数组类,一种是非数组类。

对于非数组类,因为他们有相应的二进制表示,所以是通过类加载器加载二进制表示来创建的。

而对于数组类,因为他们没有外部的二进制表示,所以数组类是由java虚拟机创建的。

java虚拟机中的类加载器又有两种,一种是虚拟机提供的引导类加载器,一种是用户自定义的类加载器。

如果是用户自定的类加载器,那么应该是ClassLoader的一个实现。用户自定义类加载器主要是为了扩展java虚拟机的功能,以支持动态加载并创建类。

链接

链接是为了让类或者接口可以被java虚拟机执行,而将类或者接口并入虚拟机运行时状态的过程。

链接具体的工作包括验证和准备类或者接口。而解析这个类或者接口中的符号引用是链接过程中的可选部分。

如果java虚拟机选择在用到类或者接口中的符号引用时才去解析他们,这叫做延迟解析。

如果java虚拟机在验证类的时候就解析符号引用,这就叫做预先解析。

验证

验证主要是为了保证类和接口的二进制表示的结构正确性。

如果类或者接口的二进制表示不满足相应的约束,则会抛出VerifyError异常。

准备

准备主要是创建类或者接口的静态字段,并使用默认值来初始化这些字段。

解析

解析是指根据运行时常量池中的符号引用来动态决定其具体值的过程。

在执行java虚拟机指令:

anewarray,checkcat, getfield, getstatic, instanceof, invokedynamic, invokeinterface, invokespecial, invokestatic, invokevirtual, ldc, ldc_w, multianewarray, new , putfield和putstatic这些指令的时候,都会去将符号引用指向运行时常量池,从而需要对符号引用进行解析。

解析可以分为类和接口的解析,字段解析,普通方法的解析,接口方法解析,方法类型和方法句柄解析,调用点限定符解析这几种。

初始化

类或者接口的初始化是指执行类或者接口的初始化方法。

只有下面的几种情况,类或者接口才会被初始化:

  1. 执行需要引用类或者接口的java虚拟机指令(new,getstatic, putstatic, invokestatic)的时候。
  2. 初次调用java.lang.invoke.Methodhandle实例的时候。
  3. 调用类库中的某些反射方法的时候。
  4. 对类的某个子类进行初始化的时候。
  5. 被选定为java虚拟机启动时候的初始类的时候。

总结

class文件经过加载,链接和初始化之后,就可以提供给JVM在运行时使用了。

本文作者:flydean程序那些事

本文链接:http://www.flydean.com/jvm-class-load-link-ini/

本文来源:flydean的博客

欢迎关注我的公众号:程序那些事,更多精彩等着您!

JVM详解之:类的加载链接和初始化的更多相关文章

  1. 《JAVA高并发编程详解》-类的加载过程简介

  2. jvm系列(一):java类的加载机制

    java类的加载机制 1.什么是类的加载 类的加载指的是将类的.class文件中的二进制数据读入到内存中,将其放在运行时数据区的方法区内,然后在堆区创建一个java.lang.Class对象,用来封装 ...

  3. Java类的加载 链接 初始化

    原文地址 Java类的加载.链接和初始化.Java字节代码的表现形式是字节数组(byte[]),而Java类在JVM中的表现形式是java.lang.Class类的对象.一个Java类从字节代码到能够 ...

  4. Android Loader详解二:使用加载器

    一个使用装载器的应用会典型的包含如下组件: 一个Activity或Fragment. 一个LoaderManager的实例. 一个加载被ContentProvider所支持的数据的CursorLoad ...

  5. 详解composer的自动加载机制

    composer是一个用PHP开发的用来管理项目依赖的工具,当你在项目中声明了依赖关系后,composer可以自动帮你下载和安装这些依赖库,并实现自动加载代码. 安装composer composer ...

  6. Spring详解(十)加载配置文件

    在项目中有些参数经常需要修改,或者后期可能会有改动时,那我们最好把这些参数放到properties文件中,在源代码中读取properties里面的配置,这样后期只需要改动properties文件即可, ...

  7. Web.xml配置详解之context-param (加载spring的xml,然后初始化bean看的)

    http://www.cnblogs.com/goody9807/p/4227296.html(很不错啊) 容器先加载spring的xml,然后初始化bean时,会为bean赋值,包括里面的占位符

  8. 《Windows驱动开发技术详解》之编程加载NT式驱动

    之前我们加载驱动都是利用INSTDRV这个应用,其原理是在注册表中写入相应的字段,这一节我们手动编写代码去加载驱动,其原理类似:

  9. 24.类的加载机制和反射.md

    目录 1类的加载连接和初始化 1.1类的加载过程 1.2类的加载器 1.2.1类的加载机制 1类的加载连接和初始化 1.1类的加载过程 类的加载过程简单为分为三步:加载->连接->初始化 ...

随机推荐

  1. MySQL 对window函数执行sum函数疑似Bug

    MySQL 对window函数执行sum函数疑似Bug 使用MySql的窗口函数统计数据时,发现一个小的问题,与大家一起探讨下. 环境配置: mysql-installer-community-8.0 ...

  2. Tomcat双击startup.bat闪退的原因及解决方式

    很久不碰Tomcat了,最近因为种种原因需要重新投入到Java Web的怀抱,所以又重新接触了Tomcat 我下载了tomcat的压缩包将其解压缩到某个位置,我这里是D盘下的tomcat文件夹中,但是 ...

  3. Maven 专题(八):配置(一)常用修改配置

    修改配置文件 通常我们需要修改解压目录下conf/settings.xml文件,这样可以更好的适合我们的使用. 此处注意:所有的修改一定要在注释标签外面,不然修改无效.Maven很多标签都是给的例子, ...

  4. java 面向对象(二十五):内部类:类的第五个成员

    内部类:类的第五个成员 1.定义: Java中允许将一个类A声明在另一个类B中,则类A就是内部类,类B称为外部类.2.内部类的分类:成员内部类(静态.非静态 ) vs 局部内部类(方法内.代码块内.构 ...

  5. java 基本语法(二) 变量的使用(重点)

    1.变量的分类1.1 按数据类型分类 详细说明://1. 整型:byte(1字节=8bit) \ short(2字节) \ int(4字节) \ long(8字节) //① byte范围:-128 ~ ...

  6. CMDB02/ 单例模式、资产采集参考命令、日志处理

    CMDB02/单例模式.资产采集参考命令.日志处理 目录 CMDB02/单例模式.资产采集参考命令.日志处理 1. 单例模式 1.1 多例模式 1.2 单例模式 1.2.1 单例模式/错误 1.2.2 ...

  7. python 并发专题(十三):asyncio (二) 协程中的多任务

    . 本文目录# 协程中的并发 协程中的嵌套 协程中的状态 gather与wait . 协程中的并发# 协程的并发,和线程一样.举个例子来说,就好像 一个人同时吃三个馒头,咬了第一个馒头一口,就得等这口 ...

  8. 作为程序员居然没用过这款神器?太out了吧。

    背景 工欲善其事,必先利其器.​后面我将陆陆续续推荐一些软件利器帮助大家提高效率(主要针对 Mac 电脑). 如果你在使用 Mac 电脑,并且没有如某些人那样安装并使用 Windows 系统,那么你可 ...

  9. 从连接器组件看Tomcat的线程模型——NIO模式

    Tomcat8之后,针对Http协议默认使用org.apache.coyote.http11.Http11NioProtocol,也就是NIO模式.通过之前的博客分析,我们知道Connector组件在 ...

  10. Jmeter操作MySQL数据库详解

    一.jmeter操作数据库的原理 jmeter不可直接操作数据库,必须通过驱动程序来间接操作,但如果数据库不是在本地而是云服务器上的话就需要通过网络来操作. jmeter通过驱动程序来完成对MySQL ...