前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >类加载器加载Class文件的过程

类加载器加载Class文件的过程

作者头像
燃192
发布2023-02-28 13:50:22
1.2K0
发布2023-02-28 13:50:22
举报
文章被收录于专栏:Java技术圈子

类加载器加载Class文件的过程

jdk8和9有一些区别,这里以8为准,9作为最后的扩充

类加载器是用于加载class文件的,我们从这里开始介绍

前言

因为底层硬件的不同,如果在不同硬件上都要做一次适配化无疑是令人奔溃的,如何让代码一次编译,处处运行呢。

计算机工程领域的任何问题都可以通过增加一个中间层来解决,字节码应运而生 Bytecode。

Java所有的指令有200个左右,一个字节(8位)可以存储236种不同的指令信息,JVM通过将字节码解释执行,屏蔽底层依赖。

Class文件

这是最简单的一段程序

代码语言:javascript
复制
public class Main {
    public static void main(String[] args) {
        System.out.println("Hello JVM");
    }
}

这是它对应的字节码文件

代码语言:javascript
复制
cafe babe 0000 0034 0022 0a00 0600 1409
0015 0016 0800 170a 0018 0019 0700 1a07
001b 0100 063c 696e 6974 3e01 0003 2829
5601 0004 436f 6465 0100 0f4c 696e 654e
756d 6265 7254 6162 6c65 0100 124c 6f63
616c 5661 7269 6162 6c65 5461 626c 6501
0004 7468 6973 0100 104c 636c 6173 7374
6573 742f 4d61 696e 3b01 0004 6d61 696e
0100 1628 5b4c 6a61 7661 2f6c 616e 672f
5374 7269 6e67 3b29 5601 0004 6172 6773
0100 135b 4c6a 6176 612f 6c61 6e67 2f53
7472 696e 673b 0100 0a53 6f75 7263 6546
696c 6501 0009 4d61 696e 2e6a 6176 610c
0007 0008 0700 1c0c 001d 001e 0100 0948
656c 6c6f 204a 564d 0700 1f0c 0020 0021
0100 0e63 6c61 7373 7465 7374 2f4d 6169
6e01 0010 6a61 7661 2f6c 616e 672f 4f62
6a65 6374 0100 106a 6176 612f 6c61 6e67
2f53 7973 7465 6d01 0003 6f75 7401 0015
4c6a 6176 612f 696f 2f50 7269 6e74 5374
7265 616d 3b01 0013 6a61 7661 2f69 6f2f
5072 696e 7453 7472 6561 6d01 0007 7072
696e 746c 6e01 0015 284c 6a61 7661 2f6c
616e 672f 5374 7269 6e67 3b29 5600 2100
0500 0600 0000 0000 0200 0100 0700 0800
0100 0900 0000 2f00 0100 0100 0000 052a
b700 01b1 0000 0002 000a 0000 0006 0001
0000 0009 000b 0000 000c 0001 0000 0005
000c 000d 0000 0009 000e 000f 0001 0009
0000 0037 0002 0001 0000 0009 b200 0212
03b6 0004 b100 0000 0200 0a00 0000 0a00
0200 0000 0b00 0800 0c00 0b00 0000 0c00
0100 0000 0900 1000 1100 0000 0100 1200
0000 0200 13

看上去还是云里雾里的很正常,不要畏难,拆分的看下去

cafe babe是Gosling定义的一个魔法数,意思是CoffeeBaby十进制表示3405691582

它的作用是标志这是一个Java类文件,如果没识别到这个,说明他不是java的类文件或者文件已经损坏,无法进行加载。

0000 0034代表当前版本号

如果对编译原理感兴趣的同学可以 javap -verbose Main.class 来读字节码文件 (idea这个插件查看 jclasslib Bytecode Viewer)

这里就先不深究

Class文件的执行模式

  1. 解释执行
  2. JIT编译执行
  3. JIT编译与解释混合执行(主流JVM默认执行方式) 混合模式的优势在于解释器在启动时先解释执行,省去编译时间。 在运行期间JVM通过热点代码统计分析,识别高频调用的方法循环与公共模块,基于JIT动态编译,将热点代码转换成机器码直接交给CPU执行。 JIT流程图如下

实际生产环境中使用JIT要注意,刚启动的JVM均是解释执行,如果流量过高可能会假死。

建议每次发布生产环境时分为 生产环境机器总数/8=发布总批次数

类加载过程

一个类型从被加载到虚拟机内存中开始,到卸载出内存为止,它的整个生命周期将会经历加载 (Loading)、验证(Verification)、

准备(Preparation)、解析(Resolution)、初始化 (Initialization)、使用(Using)和卸载(Unloading)七个阶段,

其中验证、准备、解析三个部分统称 为连接(Linking)。这七个阶段的发生顺序如图7-1所示。(有些版本描述也说是五个部分,就是把连接的三个部分都连起来并成一个阶段)

这里有一个口诀帮助记忆

家宴准备了西式菜

解析不一定是按这个顺序走的:它在某些情况下可以在初始化阶段之后再开始, 这是为了支持Java语言的运行时绑定特性(也称为动态绑定或晚期绑定)。

其他流程顺序是固定的

接下来分别探究每一个过程分别做了什么

加载

1.根据类的全类名来获取定义此类的二进制字节流。

2.并将字节流所代表的静态存储结构转换为特定的运行时数据结构

3.在内存中生成一个代表这个类的java.lang.Class实例对象

加载过程会校验cafe babe魔法数,常量池,文件长度,是否有父类等

连接

验证

这一步主要是为了安全,做更为详细的验证

文件格式验证

这里验证结束后这段字节流才被允许进入Java虚拟机内存的方法区中进行存储,后面三步是在此基础上验证的

元数据验证

除了java.lang.Object之外,所有的类都应当有父类就是这里验证的

字节码验证

保证不会出现类似于“在操作 栈放置了一个int类型的数据,使用时却按long类型来加载入本地变量表中”这样的情况。

符号引用验证

可访问性(private、protected、public、)是否可被当前类访问。

准备

类中定义的变量(即静态变量,被static修饰的变量)分配内存并设置类变量初 始值的阶段

解析

将常量池内的符号引用替换为直接引用的过程

方法的引用,java.lang.NoSuchMethodError就是这个位置抛出的

初始化

Java虚拟机才真正开始执行类中编写的Java程序代码,将主导权移交给应用程序。

执行类构造器<clinit>方法

类加载器

参考上一篇文章中 保证Java程序的稳定运作

它确保了内存中类的唯一性

先看层级结构

写代码验证

代码语言:javascript
复制
public class Main {
    public static void main(String[] args) {
        Operation operation = new Operation();

        // sun.misc.Launcher$AppClassLoader@18b4aac2
        System.out.println(operation.getClass().getClassLoader());
        // sun.misc.Launcher$ExtClassLoader@1b6d3586
        System.out.println(operation.getClass().getClassLoader().getParent());
        // null
        System.out.println(operation.getClass().getClassLoader().getParent().getParent());
    }

}

第三个应该打印BootstrapClassLoader,为什么会是个null?

因为BootstrapClassLoader是通过C/C++实现的,不存在JVM体系中所以输出为null,

类加载器具有登记制度但是并没有继承关系,以组合的方式复用父加载器的功能

  • 附加
  • JDK9中用平台加载器替代了扩展加载器的功能
本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2022-03-06,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 Java技术圈子 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 类加载器加载Class文件的过程
  • 前言
  • Class文件
  • 类加载过程
    • 加载
      • 连接
        • 验证
        • 准备
        • 解析
    • 初始化
    • 类加载器
    相关产品与服务
    对象存储
    对象存储(Cloud Object Storage,COS)是由腾讯云推出的无目录层次结构、无数据格式限制,可容纳海量数据且支持 HTTP/HTTPS 协议访问的分布式存储服务。腾讯云 COS 的存储桶空间无容量上限,无需分区管理,适用于 CDN 数据分发、数据万象处理或大数据计算与分析的数据湖等多种场景。
    领券
    问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档