JVM-类加载机制

名词解释
*.class文件的结构
查看指令: javap -verbose hello.class
包含信息:

结构信息(版本号,大小信息);

元数据(类,继承,接口,字段声明,方法声明);

方法信息(语句,表达式,异常,堆栈大小与类型,调试信息)
符号引用
符号引用符号引用就是 class 文件中的

  1. CONSTANT_Class_info
  2. CONSTANT_Field_info
  3. CONSTANT_Method_info等类型的常量
    符号引用以 一组符号来描述所引用的目标,符号可以是任何形式的字面量,只要使用时能够无歧义的定位到目标即可,使用符号引用时,被引用的目标不一定已经加载到内存中。
    直接引用
    直接引用可以是指向目标的指针,相对偏移量或是一个能间接 定位到目标的句柄。
    如果有 了直接引用,那引用的目标必定已经在内存中存在。

参考:

个人理解,如果使用符号引用,虚拟机其实也不知道具体引用的类的内存地址,那么也就无法真正的调用到该类,所以要把符号引用转为直接引用,这样就能够真正定位到类在内存中的地址,如果符号引用转直接引用失败,就说明类还没有被加载到内存中,就会报错。

https://blog.csdn.net/weixin_38106322/article/details/109239971

类加载机制概述

1、类加载器把编译好的那些".class"字节码文件给加载到JVM中,供后续代码运行来使用。
2、JVM基于自己的 字节码执行引擎,来执行加载到内存里的类。
3、类加载的时机
一个类被使用到到时候
eg:比如你的代码中有一个"main()"方法,那么JVM就会从这个"main()"方法开始执行里面的代码。他需要哪个类的时候,就会使用类加载器来加载对应的类,反正对应的类就在".class"文件中。

4、通过Java命令执行代码的大体流程如下:
java xxx 指令 在Windows下对应就是一个exe文件。dll 相当于java jar包。
C++启动程序 -》创建java虚拟机 -》java类加载器 -》加载class文件

类加载机制详解

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

加载过程分析

1. 加载

通过类全名来获取定义此类的二进制字节流,
将字节流所代表的 静态存储结构转换为方法区中运行时数据结构。
在内存中生成一个代表这个类的java.lang.Class对象,作为方法区这个类的各种数据的访问入口。
扩展:

  • 静态存储结构:数据存储于class文件的结构。
  • 运行时数据结构:数据存储于JVM的数据结构。
  • 二进制流是从.class文件中获取的。这个class文件并不一定只来源于本地,也可以来源于网络等。

2. 连接

将java二进制代码合并到java运行状态中的过程。

  • 验证:校验字节码文件的正确性 目的保证class流的格式正确。

(简单来说,这一步就是根据Java虚拟机规范,来校验你加载进来的".class"文件中的内容,是否符合指定的规范。)

  • 准备:Java虚拟机为类变量(static修饰的变量)、加载到内存中的类分配内存空间,设置默认初始值。
    • 示例代码:

public static int v=1; 在准备阶段中,v会被设置为0 在初始化的<clinit>中才会被设置为1
对于static final类型,在准备阶段就会被赋上正确的值: public static final int v=1;

  • 解析::将符号引用替换为直接引用,
    • 该阶段会把一些静态方法(符号引用,比如 main()方法)替换为指向数据所存内存的指针或句柄等(直接引用),这是所谓的静态链接过 程(类加载期间完成),
    • 动态链接:是在程序运行期间完成的将符号引用替换为直接引用

  • 3 初始化 (核心阶段)
    初始化阶段是类加载最后一个阶段,前面的类加载阶段之后,除了在加载阶段可以自定义类加载器以外,其它操作都由 JVM 主导。到了初始阶段,才开始真正执行类中定义的 Java 程序代码。如: 在初始化阶段,JVM执行类的初始化语句, 为类的静态变量赋予用户给定的初始值,执行静态代码块 。
    什么时候会初始化一个类?
    一般来说有以下一些时机:比如"new ReplicaManager()"来实例化类的对象了,此时就会触发类的加载到初始化的全过程,把这个类准备好,然后再实例化一个对象出来;(这里也说明了为什么 构造方法是在 静态代码块之后执行(先准备代码在实例化 ))
    或者是包含"main()"方法的主类,必须是立马初始化的。
    此外,这里还有一个非常重要的规则,就是如果初始化一个类的时候,发现他的父类还没初始化,那么必须先初始化他的父类

4 使用

5 卸载

http://www.cnblogs.com/ITtangtang/p/3978102.html

加载器的类型

类加载器类型总体来说可以分为以下几种:启动类加载器、其他类加载器。类的加载过程遵循双亲委派模型。
1、Bootstrap ClassLoader(启动类加载器)
JVM启动,启动类加载器 加载 Java安装目录下jre 的 "lib"目录中的核心类库

复制代码
/opt/apps/jdk1.8.0_251/jre/lib

--> rt.jar、charsets.jar等> rt.jar、charsets.jar等

2、Extension ClassLoader(扩展类加载器)
JVM启动,通过扩展类加载器加载"lib/ext"目录

复制代码
[root@iZ2zei4wx78lgr80odfj6eZ ext]# pwd# pwd

/opt/apps/jdk1.8.0_251/jre/lib/ext

3、Application ClassLoader(应用程序类加载器)
加载ClassPath 环境变量所指定的路径中的类
4、自定义类加载器
根据自己需求进行类加载

类加载器初始化过程

参见类运行加载全过程图可知其中会创建JVM启动器实例sun.misc.Launcher。
sun.misc.Launcher初始化使用了单例模式设计,保证一个JVM虚拟机内只有一个 sun.misc.Launcher实例。
在Launcher构造方法内部,其创建了两个类加载器,分别是 sun.misc.Launcher.ExtClassLoader(扩展类加载器)和sun.misc.Launcher.AppClassLoader(应 用类加载器)。
JVM默认使用Launcher的getClassLoader()方法返回的类加载器AppClassLoader的实例加载我们 的应用程序。

双亲委派模型

概述(向上寻找、向下委托)

类加载器收到类加载的请求,它首先不会自己去尝试加载这个类,而是 把这个请求委派给父类加载器完成。
每个类加载器都是如此,只有当父加载器在自己的搜索范围内找不到指定的类时(即ClassNotFoundException),
子加载器才会尝试自己去加载,这个过程为称为双亲委派模型。

AppClassLoader加载类的双亲委派机制源码

AppClassLoader 的loadClass方法最终会调用其父类ClassLoader的loadClass方法,

    1. 首先,检查一下指定名称的类是否已经加载过,如果加载过了,就不需要再加载,直接 返回。
    1. 如果此类没有加载过,那么,再判断一下是否有父加载器;如果有父加载器,则由父加 载器加载(即调用parent.loadClass(name, false);).或者是调用bootstrap类加载器来加 载。
    1. 如果父加载器及bootstrap类加载器都没有找到指定的类,那么调用当前类加载器的 findClass方法来完成类加载。
  • 对应代码位置://ClassLoader的loadClass方法,里面实现了双亲委派机制

为什么需要双亲委派模型

  • 保证类加载机制的安全性。
    • 防止病毒代码植入,自己写的java.lang.String.class类不会被加载,这样便可以防止核心 API库被随意篡改
  • 避免类的重复加载:
    • 当父亲已经加载了该类时,就没有必要子ClassLoader再加载一 次,保证被加载类的唯一性
  • 参考 : https://www.cnblogs.com/wxd0108/p/6681618.html

全盘负责委托机制

  • "全盘负责"是指当一个ClassLoder装载一个类时,除非显示的使用另外一个ClassLoder,该类 所依赖及引用的类也由这个ClassLoder载入。

如何打破双亲委派模式

  • 覆写loadClass方法

打破双亲委派模式的案例

  • tomcat类加载器
    • Common类加载器,加载Tomcat和Web应用都复用的类。
    • Catalina类加载器,加载Tomcat专有类(这些类在web应用中不可见)
    • Shared类加载器,加载所有Web应用都复用都类。(这些类tomcat中不可见)
    • WebappClassLoader:webapp私有的类加载器,只对当前webapp可见
  • Jsp类加载器,不同的jsp页面有不同的类加载器,方便实现jsp页面的热插拔。
  • 类加载机制原理
    • a. CommonClassLoader能加载的类都可以被Catalina ClassLoader和SharedClassLoader使用,从而实现了公有类库的共用

      b. CatalinaClassLoader和Shared ClassLoader自己能加载的类则与对方相互隔离

      c. WebAppClassLoader可以使用SharedClassLoader加载到的类,但各个WebAppClassLoader实例之间相互隔离,多个WebAppClassLoader是同级关系

d. 而JasperLoader的加载范围仅仅是这个JSP文件所编译出来的那一个.Class文件,它出现的目的就是为了被丢弃:当Web容器检测到JSP文件被修改时,会替换掉目前的JasperLoader的实例,并通过再建立一个新的Jsp类加载器来实现JSP文件的HotSwap功能

  • 为什么打破双亲委派模式?
    • 隔离性
      • 一个web应用可以部署多个应用程序,不同的应用程序可能会依赖同一个第三方类库的不同版本。
        • 因此需要保证每个应用程序的类库是独立的、相互隔离的。
      • web容器也有自己的类库,不能和应用程序的类库混淆,需要相互隔离
    • 共享性
      • 部署在同一个web容器中的相同类库的相同版本可以共享,否则,会有重复的类库被加载进JVM
    • 独立性
      • web容器支持jsp文件修改后不用重启,jsp文件也是要编译成.class文件的,支持HotSwap功能
  • tomcat如何打破双亲委派模式的?
  • 参考tomcat类加载机制
相关推荐
流星52112217 小时前
GC 如何判断对象该回收?从可达性分析到回收时机的关键逻辑
java·jvm·笔记·学习·算法
JanelSirry17 小时前
我的应用 Full GC 频繁,怎么优化?
jvm
JH307318 小时前
jvm,tomcat,spring的bean容器,三者的关系
jvm·spring·tomcat
DKPT21 小时前
JVM直接内存和堆内存比例如何设置?
java·jvm·笔记·学习·spring
siriuuus21 小时前
JVM 垃圾收集器相关知识总结
java·jvm
小满、1 天前
什么是栈?深入理解 JVM 中的栈结构
java·jvm·1024程序员节
百花~2 天前
JVM(Java虚拟机)~
java·开发语言·jvm
每天进步一点点dlb2 天前
JVM中的垃圾回收算法和垃圾回收器
jvm·算法
漫漫不慢.2 天前
蓝桥杯-16955 岁月流转
java·jvm·蓝桥杯
boy快快长大3 天前
【JVM】线上JVM堆内存报警,占用超90%
jvm