专栏首页iBroPro持续3分钟 - Java -09

持续3分钟 - Java -09

JVM 类加载机制

JVM 类加载机制分为五个部分:加载,验证,准备,解析,初始化,下面我们就分别来看一下这五个过程。

01

过程详解

1.1 加载

加载是类加载过程中的一个阶段,这个阶段会在内存中生成一个代表这个类的 java.lang.Class 对象,作为方法区这个类的各种数据的入口。注意这里不一定非得要从一个 Class 文件获取,这里既可以从 ZIP 包中读取(比如从 jar 包和 war 包中读取),也可以在运行时计算生成(动态代理), 也可以由其它文件生成(比如将 JSP 文件转换成对应的 Class 类)。

1.2 验证

这一阶段的主要目的是为了确保 Class 文件的字节流中包含的信息是否符合当前虚拟机的要求,并且不会危害虚拟机自身的安全。

1.3 准备

准备阶段是正式为类变量分配内存并设置类变量的初始值阶段,即在方法区中分配这些变量所使用的内存空间。注意这里所说的初始值概念,比如一个类变量定义为:

public static int address = 8080;

实际上变量 address 在准备阶段过后的初始值为 0 而不是 8080,将 address 赋值为 8080 的 put static 指令是 程序被编译后,存放于类构造器<client>方法之中。

但是注意如果声明为:

public static final int address = 8080;

在编译阶段会为 address 生成 ConstantValue 属性,在准备阶段虚拟机会根据 ConstantValue 属性将 address 赋值为 8080。

1.4 解析

解析阶段是指虚拟机将常量池中的符号引用替换为直接引用的过程。符号引用就是 class 文件中的:

1. CONSTANT_Class_info 2. CONSTANT_Field_info 3. CONSTANT_Method_info

等类型的常量。

1.5 符号引用

符号引用与虚拟机实现的布局无关,引用的目标并不一定要已经加载到内存中。各种虚拟 机实现的内存布局可以各不相同,但是它们能接受的符号引用必须是一致的,因为符号引 用的字面量形式明确定义在 Java 虚拟机规范的 Class 文件格式中。

1.6 直接引用

直接引用可以是指向目标的指针,相对偏移量或是一个能间接定位到目标的句柄。如果有 了直接引用,那引用的目标必定已经在内存中存在。

1.7 初始化

初始化阶段是类加载最后一个阶段,前面的类加载阶段之后,除了在加载阶段可以自定义类加载器以外,其它操作都由 JVM 主导。到了初始阶段,才开始真正执行类中定义的 Java 程序代码。

1.8 类构造器<client>

初始化阶段是执行类构造器<client>方法的过程。<client>方法是由编译器自动收集类中的类变量的赋值操作和静态语句块中的语句合并而成的。虚拟机会保证子<client>方法执行之前,父类的<client>方法已经执行完毕,如果一个类中没有对静态变量赋值也没有静态语句块,那么编译 器可以不为这个类生成<client>()方法。

注意以下几种情况不会执行类初始化:

  • 通过子类引用父类的静态字段,只会触发父类的初始化,而不会触发子类的初始化。
  • 定义对象数组,不会触发该类的初始化。
  • 常量在编译期间会存入调用类的常量池中,本质上并没有直接引用定义常量的类,不会触发定义常量所在的类。
  • 通过类名获取 Class 对象,不会触发类的初始化。
  • 通过 Class.forName 加载指定类时,如果指定参数 initialize 为 false 时,也不会触发类初始化。
  • 通过 ClassLoader 默认的 loadClass 方法,也不会触发初始化动作。

02

类加载器

虚拟机设计团队把加载动作放到 JVM 外部实现,以便让应用程序决定如何获取所需的类,JVM 提 供了 3 种类加载器:

2.1 启动类加载器

(Bootstrap ClassLoader)

负责加载 JAVA_HOME\lib 目录中的,或通过-Xbootclasspath 参数指定路径中的,且被 虚拟机认可(按文件名识别,如 rt.jar)的类。

2.2 扩展类加载器

(Extension ClassLoader)

负责加载 JAVA_HOME\lib\ext 目录中的,或通过 java.ext.dirs 系统变量指定路径中的类 库

2.3 应用程序类加载器

(Application ClassLoader)

负责加载用户路径(classpath)上的类库。

JVM 通过双亲委派模型进行类的加载,当然我们也可以通过继承 java.lang.ClassLoader

实现自定义的类加载器。

03

双亲委派机制

当一个类收到了类加载请求,他首先不会尝试自己去加载这个类,而是把这个请求委派给父类去完成,每一个层次类加载器都是如此,因此所有的加载请求都应该传送到启动类加载其中,只有当父类加载器反馈自己无法完成这个请求的时候(在它的加载路径下没有找到所需加载的Class),子类加载器才会尝试自己去加载。

采用双亲委派的一个好处是比如加载位于 rt.jar 包中的类 java.lang.Object,不管是哪个加载器加载这个类,最终都是委托给顶层的启动类加载器进行加载,这样就保证了使用不同的类加载器最终得到的都是同样一个 Object 对象。

图片来自网络,侵删

04

OSGI(动态模型系统)

OSGi(Open Service Gateway Initiative),是面向 Java 的动态模型系统,是 Java 动态化模块化系 统的一系列规范。

4.1 动态改变构造

OSGi 服务平台提供在多种网络设备上无需重启的动态改变构造的功能。为了最小化耦合度和促使 这些耦合度可管理,OSGi 技术提供一种面向服务的架构,它能使这些组件动态地发现对方。

4.2 模块化编程与热插拔

OSGi 旨在为实现 Java 程序的模块化编程提供基础条件,基于 OSGi 的程序很可能可以实现模块级 的热插拔功能,当程序升级更新时,可以只停用、重新安装然后启动程序的其中一部分,这对企 业级程序开发来说是非常具有诱惑力的特性。

OSGi 描绘了一个很美好的模块化开发目标,而且定义了实现这个目标的所需要服务与架构,同时 也有成熟的框架进行实现支持。但并非所有的应用都适合采用 OSGi 作为基础架构,它在提供强大 功能同时,也引入了额外的复杂度,因为它不遵守了类加载的双亲委托模型。

本文分享自微信公众号 - iBroPro(iDreamAndFaith),作者:朱家有仔名曰福建

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2020-01-22

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 谈谈 @RestController 和 @Controller

    @RestController 和 @Controller ,两者看上去就有一定的血缘关系,那么他们究竟有哪些爱恨情仇,渊源关系呢?

    子乾建建-Jeff
  • Python 小组学习 Week1-Task1

    由于我使用的是 Mac 本,Mac 自带 python2.x 版本。但自 2020 年起,将停止对 Python2.7 的支持,使用 Python3.x 版本是...

    子乾建建-Jeff
  • 持续3分钟 - Java -05

    在 Java 中最常见的就是强引用,把一个对象赋给一个引用变量,这个引用变量就是一个强引 用。当一个对象被强引用变量引用时,它处于可达状态,它是不可能被垃圾回收...

    子乾建建-Jeff
  • jvm启动加载类的全过程,全网最全一篇,告诉你什么是双亲委派机制

    回复:Java全套教程,即可获取Java基础、Java web、Java EE、spring boot等完整学习视频。

    公众号 IT老哥
  • 类加载

    启动类加载器,Bootstrap ClassLoader,加载JACA_HOME\lib,或者被-Xbootclasspath参数限定的类 扩展类加载器,Ex...

    葆宁
  • JVM如何加载.class文件

    JVM 中类的装载是由类加载器(ClassLoader)和它的子类来实现的,Java 中的类加载器是一个重要的Java 运行时系统组件,它负责在运行时查找和...

    葆宁
  • 深入探究JVM之类加载与双亲委派机制

    前面学习了虚拟机的内存结构、对象的分配和创建,但对象所对应的类是怎么加载到虚拟机中来的呢?加载过程中需要做些什么?什么是双亲委派机制以及为什么要打破双亲委派机制...

    夜勿语
  • Java类加载机制详解

    Java类加载器负责加载所有的类,系统会为所有被载入内存的类生成一个java.lang.Class实例。对于同一个类,一旦被加载如内存中,就不会被再次加载。JV...

    张申傲
  • 谈谈类加载器的双亲委派机制

    负责加载$JAVA_HOME中jre/lib/rt.jar里所有的class,由C++实现,不是ClassLoader子类

    葆宁
  • 深入理解类加载机制:拨开迷雾见真章

    我们平常写的Java代码是存储在.java文件中,这是一个文本文件,是不能直接执行的,但是这个文本文件可以被编译成为一个字节码文件(后缀为.class),这个字...

    itlemon

扫码关注云+社区

领取腾讯云代金券