目录

  1. 内存结构概述
  2. 类加载器与类的加载过程
  3. 类加载器分类
  4. ClassLoader的使用说明
  5. 双亲委派机制
  6. 其他

    1. JVM结构图

  7. 简图

image.png

  1. 详细图

image.png

2. 类加载器与类的加载过程

  1. 类加载器的作用

image.png
一、加载阶段

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

image.png

  1. 类的加载过程

image.png
image.png
加载
1.通过一个类的全限定名获取定义此类的二进制字节流
2.将这个字节流所代表的静态存储结构转化为方法区的运行时数据结构
3.在内存中生成一个代表这个类的java.lang.Class对象,作为方法区这个类的各种数据的访问入口
image.png
二、链接阶段
image.png
验证(Verify)阶段回去验证class文件是否是以CAFEBABE开头的文件
image.png
准备(Prepare)阶段,会个基本类型a设置为0
image.png
解析(Resolve)阶段会将字节码常量池中的符号引用(#1,#2,#3,#4….)转换为直接引用
image.png
三、初始化阶段
image.png

下面是将java的java类
image.png
下面是class类反编译的文件
image.png
其中是初始化构造器,是用来初始化静态变量
复杂例子:
image.png
num先赋值为1,然后赋值为2
image.png
覆盖赋值的例子,number在连接的准备阶段就会赋值为0,在初始化阶段先赋值为20在赋值为10
image.png
字节码层面的解读
image.png
构造器初始化是在init方法中进行的
image.png
image.png
调用的类如果有父类就要先加载、初始化父类,例子如下
image.png
image.png

类的加载只会执行一次,在类的加载完后,jvm会将类的信息加载到元空间(jdk8叫元空间,jdk8以前叫永久代),元空间是在服务器的内存(也就是在本地内存缓存起来了)开辟一个空间来存储数据而不是在jvm中开辟空间,类的加载过程中只会调用一次clinit方法。在开发中要避免多个线程同时去调用同一个类的静态字段。
例子如下:模拟两个线程初始化cinit
image.png
这样线程就一下是阻塞的状态,开发中要避免这种情况出现
image.png

3. 类加载器的分类

image.png
image.png
例子:获取各种类加载器
image.png
image.png
引导类加载器
image.png
扩展类加载器
image.png
系统类加载器
image.png
查看引导类加载器能够加载的api路径
image.png
image.png
扩展类加载器加载的路径
image.png
image.png
image.png
image.png
自定义类的加载器的例子:
image.png
image.png

关于ClassLoader
image.png
image.png
image.png

4. 双亲委派机制

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

工作原理
1)如果一个类加载器收到了类加载请求,它并不会自己先去加载,而是把这个请求委托给父类的加载器去执
2)如果父类加载器还存在其父类加载器,则进一步向上委托,依次递归请求最终将到达顶层的启动类加载器;
3)如果父类加载器可以完成类加载任务,就成功返回,倘若父类加载器无法完成此加载任务,子加载器才会尝试自己去加载,这就是双亲委派模式
image.png
image.png
image.png
优势:避免类的重复加载;保护程序安全,防止核心API被随意篡改
自定义类:java.lang. string
自定义类:java.lang. Shkstart
Java. lang Securityexception: prohibited package name: Java. lang
例子如下:
image.png
沙箱安全机制
自定义 String类,但是在加载自定义 String类的时候会率先使用引导类加载器加载,而引导类加载器在加载的过程中会先加载jdk自带的文件(rt.jar包中java\lang\String.class),报错信息说没有main方法,就是因为加载的是rt.jar包中的 String类。这样可以保证对java核心源代码的保护,这就是沙箱安全机制。

5. 补充内容

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

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

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

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

类的主动使用和被动使用
Java程序对类的使用方式分为:主动使用和被动使用。
主动使用,又分为七种情况:

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

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