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-加载,链接,初始化的更多相关文章

  1. JVM加载的初始化类

    首先Throws(抛出)几个自己学习过程中一直疑惑的问题: 1.什么是类加载?什么时候进行类加载? 2.什么是类初始化?什么时候进行类初始化? 3.什么时候会为变量分配内存? 4.什么时候会为变量赋默 ...

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

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

  3. 全面解析JVM加载中初始化的时机

    JVM类加载过程 JVM类加载过程分为几个阶段,分别是加载.验证.准备.解析和初始化.加载是把二进制字节码载入内存,验证是校验字节流中包含的信息是否符合当要求,准备是为静态变量分配内存并设置静态变量初 ...

  4. 关于JVM加载class文件和类的初始化

    关于JVM加载class文件和类的初始化 1.JVM加载Class文件的原理机制 1.1.装载 查找并加载类的二进制数据 1.2.链接 验证:确保被加载类的正确性.(安全性考虑) 准备:为类的静态变量 ...

  5. JVM加载class文件的原理

    当Java编译器编译好.class文件之后,我们需要使用JVM来运行这个class文件.那么最开始的工作就是要把字节码从磁盘输入到内存中,这个过程我们叫做[加载 ].加载完成之后,我们就可以进行一系列 ...

  6. jvm 加载class文件过程

    jvm 加载class文件分为装载-链接-初始化三个过程. load -------->link verify prepare resolve     ---------->initial ...

  7. Java提高篇——JVM加载class文件的原理机制

    在面试java工程师的时候,这道题经常被问到,故需特别注意. 1.JVM 简介 JVM 是我们Javaer 的最基本功底了,刚开始学Java 的时候,一般都是从“Hello World ”开始的,然后 ...

  8. JVM加载类的过程,双亲委派机制中的方法

    JVM加载类的过程: 1)JVM中类的整个生命周期: 加载=>验证=>准备=>解析=>初始化=>使用=>卸载  1.1.加载 类的加载阶段,主要是获取定义此类的二进 ...

  9. JVM加载class文件的原理机制(转)

    JVM加载class文件的原理机制 1.Java中的所有类,必须被装载到jvm中才能运行,这个装载工作是由jvm中的类装载器完成的,类装载器所做的工作实质是把类文件从硬盘读取到内存中 2.java中的 ...

  10. JVM学习(二)JVM加载类

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

随机推荐

  1. JavaSE高级之GUI编程

    下面主要用到了java中的swing进行界面设计,当然java的GUI不如C#的设计的好看,不过原理还是要会的. 1. GUI Graphical User Interface 用户图形界面 a) 主 ...

  2. 1Z0-053 争议题目解析46

    1Z0-053 争议题目解析46 考试科目:1Z0-053 题库版本:V13.02 题库中原题为: 46.What happens when you run the SQL Tuning Adviso ...

  3. Java类初始化

    Java类初始化 成员变量的初始化和构造器 如果类的成员变量在定义时没有进行显示的初始化赋值,Java会给每个成员变量一个默认值 对于  char.short.byte.int.long.float. ...

  4. Java 实现批量重命名,亲测可用(精简版)

    之前在网上下载了很多视频,解压缩后,发现里面每个文件前面都有一长串的网址,导致我根本看不清每个视频的名字到底叫什么? 网上搜了一些批量重命名的方法,可都不是我想要的,既然这样,干脆自己动手用Java写 ...

  5. SignalR的Javascript客户端API使用方式整理

    SignalR的服务端提供了两种实现方式,分别是PersistentConnection和Hub,这两种方式的侧重点不同: PersistentConnection更接近于底层,编程接口比较简单,传输 ...

  6. 关于dijkstra算法的一点理解

    最近在准备ccf,各种补算法,图的算法基本差不多看了一遍.今天看的是Dijkstra算法,这个算法有点难理解,如果不深入想的话想要搞明白还是不容易的.弄了一个晚自习,先看书大致明白了原理,就根据书上的 ...

  7. js树形控件—zTree使用总结

    0 zTree简介 树形控件的使用是应用开发过程中必不可少的.zTree 是一个依靠 jQuery 实现的多功能 “树插件”.优异的性能.灵活的配置.多种功能的组合是 zTree 最大优点. 0.0 ...

  8. 从Insider计划看Win10的发展

    Windows 10 Insider计划是微软为了更好的倾听用户的需求而推出的用户测试项目,参与该项目的 Insider可以免费使用Windows 10 预览版.同时这些用户还需要对 Windows ...

  9. Xamarin Studio在Mac环境下的配置和Xamarin.iOS常用控件的示例

    看过好多帖子都是Win环境装XS,Mac只是个模拟器,讲解在Mac环境下如何配置Xamarin Studio很少,也是一点点找资料,东拼西凑才把Xamarin Studio装在Mac上跑起来,如下: ...

  10. .net源码分析 - ConcurrentDictionary<TKey, TValue>

    List源码分析 Dictionary源码分析 ConcurrentDictionary源码分析 继上篇Dictionary源码分析,上篇讲过的在这里不会再重复 ConcurrentDictionar ...