引导类加载器和启动类加载器(类加载子系统)

1. jvm结构图
  1. 简图

引导类加载器和启动类加载器(类加载子系统)(1)

  1. 详细图

引导类加载器和启动类加载器(类加载子系统)(2)

2. 类加载器与类的加载过程
  1. 类加载器的作用

引导类加载器和启动类加载器(类加载子系统)(3)

一、加载阶段

  • 类加载器子系统负责从文件系统或者网络中加载class文件,class文件在文件开头有特定的文件标识
  • Classloader只负责class文件的加载,至于它是否可以运行,则由ExecutionEngine决定
  • 加载的类信息存放于一块称为方法区的内存空间。除了类的信息外,方法区中还会存放运行时常量池信息,可能还包括字符串字面量和数字常量(这部分常量信息是class文件中常量池部分的内存映射)
  1. 类加载器ClassLoader角色

引导类加载器和启动类加载器(类加载子系统)(4)

  1. 类的加载过程

引导类加载器和启动类加载器(类加载子系统)(5)

引导类加载器和启动类加载器(类加载子系统)(6)

加载

1.通过一个类的全限定名获取定义此类的二进制字节流

2.将这个字节流所代表的静态存储结构转化为方法区的运行时数据结构

3.在内存中生成一个代表这个类的java.lang.Class对象,作为方法区这个类的各种数据的访问入口

引导类加载器和启动类加载器(类加载子系统)(7)

二、链接阶段

引导类加载器和启动类加载器(类加载子系统)(8)

验证(Verify)阶段回去验证class文件是否是以CAFEBABE开头的文件

引导类加载器和启动类加载器(类加载子系统)(9)

准备(Prepare)阶段,会个基本类型a设置为0

引导类加载器和启动类加载器(类加载子系统)(10)

解析(Resolve)阶段会将字节码常量池中的符号引用(#1,#2,#3,#4....)转换为直接引用

引导类加载器和启动类加载器(类加载子系统)(11)

三、初始化阶段

下面是将java的Java类

下面是class类反编译的文件

其中<init>是初始化构造器,<clinit>是用来初始化静态变量

复杂例子:

引导类加载器和启动类加载器(类加载子系统)(12)

num先赋值为1,然后赋值为2

引导类加载器和启动类加载器(类加载子系统)(13)

覆盖赋值的例子,number在连接的准备阶段就会赋值为0,在初始化阶段先赋值为20再赋值为10

引导类加载器和启动类加载器(类加载子系统)(14)

字节码层面的解读

引导类加载器和启动类加载器(类加载子系统)(15)

构造器初始化是在init方法中进行的

引导类加载器和启动类加载器(类加载子系统)(16)

引导类加载器和启动类加载器(类加载子系统)(17)

调用的类如果有父类就要先加载、初始化父类,例子如下

引导类加载器和启动类加载器(类加载子系统)(18)

引导类加载器和启动类加载器(类加载子系统)(19)

类的加载只会执行一次,在类的加载完后,jvm会将类的信息加载到元空间(jdk8叫元空间,jdk8以前叫永久代),元空间是在服务器的内存(也就是在本地内存缓存起来了)开辟一个空间来存储数据而不是在jvm中开辟空间,类的加载过程中只会调用一次clinit方法。在开发中要避免多个线程同时去调用同一个类的静态字段。

例子如下:模拟两个线程初始化cinit

引导类加载器和启动类加载器(类加载子系统)(20)

这样线程就一下是阻塞的状态,开发中要避免这种情况出现

引导类加载器和启动类加载器(类加载子系统)(21)

3. 类加载器的分类

引导类加载器和启动类加载器(类加载子系统)(22)

引导类加载器和启动类加载器(类加载子系统)(23)

例子:获取各种类加载器

引导类加载器和启动类加载器(类加载子系统)(24)

引导类加载器和启动类加载器(类加载子系统)(25)

引导类加载器

引导类加载器和启动类加载器(类加载子系统)(26)

扩展类加载器

引导类加载器和启动类加载器(类加载子系统)(27)

系统类加载器

引导类加载器和启动类加载器(类加载子系统)(28)

查看引导类加载器能够加载的api路径

引导类加载器和启动类加载器(类加载子系统)(29)

引导类加载器和启动类加载器(类加载子系统)(30)

扩展类加载器加载的路径

引导类加载器和启动类加载器(类加载子系统)(31)

引导类加载器和启动类加载器(类加载子系统)(32)

引导类加载器和启动类加载器(类加载子系统)(33)

引导类加载器和启动类加载器(类加载子系统)(34)

自定义类的加载器的例子:

引导类加载器和启动类加载器(类加载子系统)(35)

引导类加载器和启动类加载器(类加载子系统)(36)

关于ClassLoader

引导类加载器和启动类加载器(类加载子系统)(37)

引导类加载器和启动类加载器(类加载子系统)(38)

引导类加载器和启动类加载器(类加载子系统)(39)

4. 双亲委派机制

概念:

Java虚拟机对c1ass文件采用的是按需加载的方式,也就是说当需要使用该类时才会将它的class文件加载到内存生成class对象。而且加载某个类的class文件时,Java虚拟机采用的是双亲委派模式,即把请求交由父类处理,它是一种任务委派模式。

工作原理

1)如果一个类加载器收到了类加载请求,它并不会自己先去加载,而是把这个请求委托给父类的加载器去执

2)如果父类加载器还存在其父类加载器,则进一步向上委托,依次递归请求最终将到达顶层的启动类加载器;

3)如果父类加载器可以完成类加载任务,就成功返回,倘若父类加载器无法完成此加载任务,子加载器才会尝试自己去加载,这就是双亲委派模式

引导类加载器和启动类加载器(类加载子系统)(40)

引导类加载器和启动类加载器(类加载子系统)(41)

引导类加载器和启动类加载器(类加载子系统)(42)

优势:避免类的重复加载;保护程序安全,防止核心API被随意篡改

自定义类:java.1ang. string

自定义类:java.lang. Shkstart

Java. lang Securityexception: prohibited package name: Java. lang

例子如下:

引导类加载器和启动类加载器(类加载子系统)(43)

沙箱安全机制

自定义 string类,但是在加载自定义 string类的时候会率先使用引导类加载器加载,而引导类加载器在加载的过程中会先加载jdk自带的文件(rt.jar包中java\lang\ string,c1ass),报错信息说没有main方法,就是因为加载的是rt.jar包中的 string类。这样可以保证对java核心源代码的保护,这就是沙箱安全机制。

5. 补充内容

1.在JWM中表示两个c1ass对象是否为同一个类存在两个必要条件:

  • 类的完整类名必须一致,包括包名。
  • 加载这个类的c1 assloader(指C1 assloader实例对象)必须相同。·

2.换句话说,在JⅥ中,即使这两个类对象(c1ass对象)来源同一个C1ass文件,被同一个虚拟机所加载,但只要加载它们的C1 assloader实例对象不同,那么这两个类对象也是不相等的。

类加载器的引用

JM必须知道一个类型是由启动加载器加载的还是由用户类加载器加载的。如果一个类型是由用户类加载器加载的,那么JM会将这个类加载器的一个引用作为类型信息的一部分保存在方法区中。当解析一个类型到另一个类型的引用的时候,JW需要保证这两个类型的类加载器是相同的。

类的主动使用和被动使用

Java程序对类的使用方式分为:主动使用和被动使用。

主动使用,又分为七种情况:

  • 创建类的实例
  • 访问某个类或接口的静态变量,或者对该静态变量赋值
  • 调用类的静态方法
  • 反射(比如:c1ass. forname("com, atguigu.Test")
  • 初始化一个类的子类
  • Java虚拟机启动时被标明为启动类的类
  • JDK7开始提供的动态语言支持:java.1ang. invoke. Methodhand1e实例的解析结果ree getstatic、 REE putstatic、 REF invokestatic句柄对应的类没有初始化,则初始化

除了以上七种情况,其他使用Java类的方式都被看作是对类的被动使用,都不会导致类的初始化。

,

免责声明:本文仅代表文章作者的个人观点,与本站无关。其原创性、真实性以及文中陈述文字和内容未经本站证实,对本文以及其中全部或者部分内容文字的真实性、完整性和原创性本站不作任何保证或承诺,请读者仅作参考,并自行核实相关内容。文章投诉邮箱:anhduc.ph@yahoo.com

    分享
    投诉
    首页