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. DDD 领域驱动设计-三个问题思考实体和值对象(续)

    上一篇:DDD 领域驱动设计-三个问题思考实体和值对象 说实话,整理现在这一篇博文的想法,在上一篇发布出来的时候就有了,但到现在才动起笔来,而且写之前又反复读了上一篇博文的内容及评论,然后去收集资料, ...

  2. C算法编程题(七)购物

    前言 上一篇<C算法编程题(六)串的处理> 有些朋友看过我写的这个算法编程题系列,都说你写的不是什么算法,也不是什么C++,大家也给我提出用一些C++特性去实现问题更方便些,在这里谢谢大家 ...

  3. ios 静态库冲突的解决办法

    最近在做一个 iOS 的 cocos2d-x 项目接入新浪微博 SDK 的时候被“坑”了,最后终于顺利的解决了.发现网上也有不少人遇到一样的问题,但是能找到的数量有限的解决办法写得都不详细,很难让人理 ...

  4. react-native 学习之TextInput组件篇

    /** * Sample React Native App * https://github.com/facebook/react-native */ 'use strict'; import Rea ...

  5. ZOJ Problem Set - 1392 The Hardest Problem Ever

    放了一个长长的暑假,可能是这辈子最后一个这么长的暑假了吧,呵呵...今天来实验室了,先找了zoj上面简单的题目练练手直接贴代码了,不解释,就是一道简单的密文转换问题: #include <std ...

  6. HuffmanTree的浅析和在C#中的算法实现

    无论是在我们的开发项目中,还是在我们的日常生活中,都会较多的涉及到文件压缩.谈到文件压缩,可能会有人想问文件压缩到底是怎么实现的,实现的原理是什么,对于开发人员来说,怎么实现这样一个压缩的功能. 接下 ...

  7. 用JqueryUI的Dialog+IFrame实现仿模态窗口效果

    大家有没有想过这样一个问题,当我点击某个图片的时候,我想弹出这个图片信息的详情并修改,于是你首先想到的是不是window.open?window.open方法确实可以,但是有它的局限性,比如,标题显示 ...

  8. 大小写互换-"数字字符串"转换成数字

    今天穿着hacker浑浊马甲在百度编程课堂实训习题中发现了这个很简单的问题,就做了下. 为了考虑输入的是否是数字,结果写好后竟然超时了. 不过里面用到的将字符串装换成数字的方法,感觉是个收获,因此在此 ...

  9. VS Code - Debugger for Chrome调试JavaScript的两种方式

    VS Code - Debugger for Chrome调试JavaScript的两种方式 最近由于出差的缘故,博客写的不是很多,一直想写一篇VS Code - Debugger for Chrom ...

  10. 机器学习 1 linear regression 作业

    话说学机器学习,不写代码就太扯淡了.好了,接着上一次的线性回归作业. hw1作业的链接在这: http://speech.ee.ntu.edu.tw/~tlkagk/courses/ML_2016/L ...