JVM-加载,链接,初始化
Java Virtual Machine 动态的加载,链接和初始化类和接口。那么,Class 二进制文件是怎样被 JVM 加载到内存中的?JVM 如何描述一个 Java 类?类或接口怎么才能让 JVM执行?类或接口又是怎么初始化的?在JVM内部Java类的是以什么形式存在?
带着这些问题,本文将讨论:
- JVM 加载
- JVM 链接
- JVM 初始化
- JVM 内部对象表示
一个 Class 文件被 JVM 读取,然后经过加载,链接和初始化这些逻辑阶段,变成可被 JVM 识别的格式,最终在内存中的体现就是一个 java.lang.Class 对象。在虚拟机规范中并没有规定这些阶段按顺序进行,HotSpot VM 有些阶段就是交叉进行的。

1. JVM 加载
加载就是从字节流中,按照 Class 文件的格式解析出类或接口,并创建相应的类或接口。类加载的时机是在解析字节码中常量池符号的时候,比如Class.forName()、ClassLoader.loadClass()、反射和JNI_FindClass都能引发类加载。当 JVM 启动时,将会使用如下几种类加载器:
- Bootstrap Class Loader
启动类加载器,它负责加载位于 <JAVA_HOME>\jre\lib 目录的 Java 核心类库(如 rt.jar),它是使用本地方法编写,不是一个 Java 类。由它加载的类,当调用 getClassLoader() 时,返回 null 。
- Extension Class Loader
扩展类加载器,它负责加载位于 <JAVA_HOME>\jre\lib\ext 目录中的 Class 文件,由 sun.misc.Launcher$ExtClassLoader 实现。
- System Class Loader
系统类加载器,也叫应用程序类加载器(Application class loader),它负责加载位于 CLASSPATH 环境变量路径上的类库。程序的默认加载器就是它,当然也可以自定义加载器。它由 sun.misc.Launcher$AppClassLoader 实现。
- User-Defined Class Loader
用户自定义类加载器。
为了避免重复加载,和保证 Java 类型体系的安全,JVM 在加载时,使用双亲委派模型(Parents Delegation Model),它表示类加载器的一种层次关系,使用组合来实现。

当一个类加载器加载一个类时,首先它不会先尝试自己加载这个类,而是把这个加载请求委派给父类加载器,每层均是如此,把这个请求逐层上传,直到顶层的启动类加载器,只有当父类加载器反馈自己无法完成加载时,子类加载器才会自己去加载。
根据 class 文件,类加载器在内存中创建一个 java.lang.Class 对象与之对应。在运行时,类或接口的全限定名称并不是其唯一标识,而是使用名字和加载它的类加载器共同标识的。所以当使用 instanceof,equals() 判断两个类是否相同时的必要条件是,两个类由同一个类加载器加载。在 JVM 内部有一个系统字典,它记录了系统加载的所有类,类加载器等信息,为其他模块提供检索服务。
2. JVM 链接
class 文件之间通过符号引用建立关系(符号引用以字符串的形式存在),JVM 动态加载类或接口,通过动态链接把它们链接起来,实现方法调用和相互引用。链接可分为验证,准备和解析。
- 验证
用于确保 Class 文件符合 JVM 的要求,验证字节码的正确性,验证类的元数据信息。
- 准备
为类变量分配内存并赋值各类型的默认值,如果是 final static 修饰的字段,直接会被初始化为指定的值。
- 解析
把常量池中的符号引用转换为直接引用,即运行时实际内存地址,主要有类,接口,字段和方法这 4 类符号引用。
3. JVM 初始化
初始化阶段,就是执行 Java 的初始化方法,有两个方法:一个是类初始化方法 <clinit>(静态块,语句初始化);一个是实例初始化方法 <init>(构造函数),这两个方法都是由编译器自动生成的,在初始化阶段由 JVM 自身隐式调用。
JVM 会保证父类先于子类执行 <clinit> 方法,也就是说父类的静态块和变量初始化操作先于子类的执行,在多线程环境下,JVM 会保证 <clinit> 方法的线程安全。
4. JVM 内部对象表示
HotSpot 是基于 C++ 实现的,其内部使用 OOP-Klass 二分模型来描述一个Java类的信息,其中OOP(Ordinary Object Pointer, OOPS),普通对象指针,描述对象实例信息;Klass,用来描述 Java类。我们知道 多态 是面向对象的重要特点,JVM 就是通过 Klass 实现Java 对象的分发功能。

每加载一个 Java 类,JVM 会创建一个 instanceKlass 对象(或 arrayKlass)在内部描述它;每创建一个 Java 对象,JVM 内部也会创建一个 OOP 对象来表示它。(注意区别)
(1)OOP 普通对象指针
一个 Java 对象在 JVM 内部包含两个部分,instanceOop 和实例数据。其中 instanceOop 又被成为对象头,对象头包括以下两部分信息:
- Mark Word:_mark字段,存储对象运行时信息,如哈希吗,GC分代年龄,锁信息等。数据类型为 markOop,以字长为单位,64位可以使用压缩。
- 元数据指针:指向描述类型的 Klass 对象的指针,Klass包含此类的元数据(meta-data)。

(2)instanceKlass
Klass类型的对象,是访问类元数据的入口。JVM 对每个已加载的 Java 类,内部都创建一个 instanceKlass 对象,它描述了 类的元数据,类的方法,字段,类加载器,常量等,拥有一个 Java 类运行时所需的所有信息。

instanceKlass 引用了与之对应的 java.lang.Class 对象,后者是前者的 Java 镜像。在HotSpot 内部使用 klassOop 来访问 instanceKlass,VM内部会维护一个系统字典表,记录所有已经加载的类。
JVM-加载,链接,初始化的更多相关文章
- JVM加载的初始化类
首先Throws(抛出)几个自己学习过程中一直疑惑的问题: 1.什么是类加载?什么时候进行类加载? 2.什么是类初始化?什么时候进行类初始化? 3.什么时候会为变量分配内存? 4.什么时候会为变量赋默 ...
- Java类的加载 链接 初始化
原文地址 Java类的加载.链接和初始化.Java字节代码的表现形式是字节数组(byte[]),而Java类在JVM中的表现形式是java.lang.Class类的对象.一个Java类从字节代码到能够 ...
- 全面解析JVM加载中初始化的时机
JVM类加载过程 JVM类加载过程分为几个阶段,分别是加载.验证.准备.解析和初始化.加载是把二进制字节码载入内存,验证是校验字节流中包含的信息是否符合当要求,准备是为静态变量分配内存并设置静态变量初 ...
- 关于JVM加载class文件和类的初始化
关于JVM加载class文件和类的初始化 1.JVM加载Class文件的原理机制 1.1.装载 查找并加载类的二进制数据 1.2.链接 验证:确保被加载类的正确性.(安全性考虑) 准备:为类的静态变量 ...
- JVM加载class文件的原理
当Java编译器编译好.class文件之后,我们需要使用JVM来运行这个class文件.那么最开始的工作就是要把字节码从磁盘输入到内存中,这个过程我们叫做[加载 ].加载完成之后,我们就可以进行一系列 ...
- jvm 加载class文件过程
jvm 加载class文件分为装载-链接-初始化三个过程. load -------->link verify prepare resolve ---------->initial ...
- Java提高篇——JVM加载class文件的原理机制
在面试java工程师的时候,这道题经常被问到,故需特别注意. 1.JVM 简介 JVM 是我们Javaer 的最基本功底了,刚开始学Java 的时候,一般都是从“Hello World ”开始的,然后 ...
- JVM加载类的过程,双亲委派机制中的方法
JVM加载类的过程: 1)JVM中类的整个生命周期: 加载=>验证=>准备=>解析=>初始化=>使用=>卸载 1.1.加载 类的加载阶段,主要是获取定义此类的二进 ...
- JVM加载class文件的原理机制(转)
JVM加载class文件的原理机制 1.Java中的所有类,必须被装载到jvm中才能运行,这个装载工作是由jvm中的类装载器完成的,类装载器所做的工作实质是把类文件从硬盘读取到内存中 2.java中的 ...
- JVM学习(二)JVM加载类
一.什么是类的加载 类的加载指的是将类的.class文件中的二进制数据读入到内存中,将其放在运行时数据区的方法区内,然后在堆区创建一个java.lang.Class对象,用来封装类在方法区内的数据结构 ...
随机推荐
- Why is HttpContext.Current null after await?
今天在对项目代码进行异步化改进的时候,遇到一个奇怪的问题(莫笑,以前没遇过),正如标题一样,HttpContext.Current 在 await 异步执行之后,就会变为 null. 演示代码: pu ...
- (三)WebGIS前端地图显示之根据地理范围换算出瓦片行列号的原理(核心)
文章版权由作者李晓晖和博客园共有,若转载请于明显处标明出处:http://www.cnblogs.com/naaoveGIS/. 1.前言 在上一节中我们知道了屏幕上一像素等于实际中多少单位长度(米或 ...
- 【JVM】JVM系列之垃圾回收(二)
一.为什么需要垃圾回收 如果不进行垃圾回收,内存迟早都会被消耗空,因为我们在不断的分配内存空间而不进行回收.除非内存无限大,我们可以任性的分配而不回收,但是事实并非如此.所以,垃圾回收是必须的. 二. ...
- android防止内存溢出浅析
Android的虚拟机是基于寄存器的Dalvik,它的最大堆大小一般是16M.但是Android采用的是Java语言编写,所以在很大程度上,Android的内存机制等同于Java的内存机制,在刚开始开 ...
- 从零开始,搭建博客系统MVC5+EF6搭建框架(2),测试添加数据、集成Autofac依赖注入
一.测试仓储层.业务层是否能实现对数据库表的操作 1.创建IsysUserInfoRepository接口来继承IBaseRepository父接口 namespace Wchl.WMBlog.IRe ...
- 7.5 数据注解特性--MaxLength&&MinLength
MaxLength attribute can be applied to a string or array type property of a domain class. EF Code Fir ...
- 部署.NET开发环境
昨晚把家里的电脑重新部署.NET开发环境.从晚上21点安装到今天凌晨3点多才完成,还算顺利,但是耗时最漫长莫过于在安装Visual Studio 2015 Update3...... 第一,全新安装W ...
- IIS事件查看器_WebServer事件查看器_帮助查看IIS-Web服务器事件执行日志
IIS服务器是我们常用的Web站点部署工具,而我们有时可能遇到IIS服务器的应用程序池莫名其妙的关闭了,或者是其他未知原因等等,我们这是可以通过微软提供的WebServer(Web服务事件查看器),来 ...
- 【C#】分享带等待窗体的任务执行器一枚
-------------201504161039更新------------- 更新内容: IWaitForm接口删除System.Windows.Forms.DialogResult Dialog ...
- How do I see all foreign keys to a table or column?
down voteaccepted For a Table: SELECT TABLE_NAME,COLUMN_NAME,CONSTRAINT_NAME, REFERENCED_TABLE_NAME, ...