JVM基础学习---1、JVM总体机制、类加载机制

简介: JVM基础学习---1、JVM总体机制、类加载机制

1、JVM总体机制

1.1 JVM概念

f17ced7c75774076ba7e191a0cce011b.pngJVM:Java Virtual Machine,翻译过来是Java虚拟机。

JRE:Java Runtime Environment,翻译过来是Java运行时环境。

JDK:Java Development Ki

JDK:Java Development Kits,翻译过来是Java开发工具包

JDK=JRE+Java开发辅助工具

JVM工作的总体机制

1、Java源程序编译运行过程

Java源程序–>编译–>字节码文件–>放到JVM上运行

2、JVM工作的总体运行机制

  • 第一步:使用类加载子系统将*.class字节码文件加载到JVM内存
  • 第二步:在JVM的内存空间存储相关数据。
  • 第三步:在执行引擎中将*.class字节码文件翻译成CPU能够执行的指令。
  • 第四步:将指令发给CPU执行。
  • 7fdc4d3b7afa4c27aaf49a728326f5d7.png

2、类加载机制

2.1 类加载器

1、概念

  1. 类加载器子系统负责从文件系统或者网络中加载*.class字节码文件。
  2. 字节码文件开头必须有特定的文件标识。如果使用二进制文件查看工具打开Java编译得到的字节码文件,会发现,文件开头是:CA FE BA BE。它们都是十六进制数的符号。
  3. ClassLoader只负责字节码文件的加载,至于它是否可以运行,则由Execution Engine执行引擎决定的。
  4. 加载的类信息存放于一块称为方法区的内存空间。除了类的信息外,方法区中还会存放运行时常量池信息,可能还包括字符串字面量和数字字面量(这部分常量信息是字节码文件中常量池部分的内存映射)。

8cb1bddc0b6c4755ba2260aa2ed7fd7d.png

2、分类

64ceb8acecce48f29eb41e8df301683f.png

JVM中类加载器分为四种:前三种为虚拟机自带的加载器。

中文名称 英文名称 说明
启动类加载器 Bootstrap C++语言编写,不是ClassLoader子类·,Java中为null
扩展类加载器 Extension sun.misc.Launcher.ExtClassLoader
应用类加载器 AppClassLoader sun.misc.Launcher.AppClassLoader

自定义类加载器


程序员自己开发一个类继承java.lang.ClassLoader,定制类加载方式

3、父子关系

  • 父子关系1:启动类加载器是扩展类加载器的父加载器
  • 父子关系2:扩展类加载器是应用类加载器的父加载器

注意:这里说的父子关系不是通过继承实现的,不是类型上的父子关系。而是在子加载器中通过parent属性指向父加载器这样建立的—是对象之间逻辑上的父子关系。

4、通过代码查看类加载器

// 1.获取Person类的Class对象
// 2.通过Class对象进一步获取它的类加载器对象
ClassLoader appClassLoader = Person.class.getClassLoader();
// 3.获取appClassLoader的全类名
String appClassLoaderName = appClassLoader.getClass().getName();
// 4.打印appClassLoader的全类名
// sun.misc.Launcher$AppClassLoader
System.out.println("appClassLoaderName = " + appClassLoaderName);
// 5.通过appClassLoader获取扩展类加载器(父加载器)
ClassLoader extClassLoader = appClassLoader.getParent();
// 6.获取extClassLoader的全类名
String extClassLoaderName = extClassLoader.getClass().getName();
// 7.打印extClassLoader的全类名
// sun.misc.Launcher$ExtClassLoader
System.out.println("extClassLoaderName = " + extClassLoaderName);
// 8.通过extClassLoader获取启动类加载器(父加载器)
ClassLoader bootClassLoader = extClassLoader.getParent();
// 9.由于启动类加载器是C语言开发的,在Java代码中无法实例化对象,所以只能返回null值
System.out.println("bootClassLoader = " + bootClassLoader);

2.2 双亲委派机制

『双亲委派机制』这个名字不能顾名思义。在中文语境下,双亲是指父母;但是这里实际上是指『爸爸』和『爷爷』。所以我觉得应该叫:祖孙三代,比拼啃老机制,更贴切。

1、机制简介

06e4ac8f98484776a82912859dbddad9.png

当我们需要加载任何一个范围内的类时,首先要找到这个范围对应的类加载器

但是当前这个类加载器不是马上开始查找

当前类加载器会将任务交给上一级类加载器

上一级类加载器继续上交任务,一直到最顶级的启动类加载器

启动类加载器开始在自己负责的范围内查找

如果能找到,则直接开始加载

如果找不到,则交给下一级的类加载器继续查找

一直到应用程序类加载器

如果应用程序类加载器同样找不到要加载的类,那么就会抛出ClassNotFoundException。

2、实验

(1)实验1

第一步:在与JDK无关的目录下创建Hello.java

public class Hello {
  public static void main(String[] args){
    System.out.println("AAA");
  }
}
  • 第二步:编译Hello.java
  • 第三步:将Hello.class文件移动到$JAVA_HOME/jre/classes目录(没有就自己创建一个)下
  • 第四步:修改Hello.java
public class Hello {
  public static void main(String[] args){
    System.out.println("BBB");
  }
}
  • 第五步:编译Hello.java
  • 第六步:将Hello.class文件移动到$JAVA_HOME/jre/lib/ext/classes目录(没有就自己创建一个)下
  • 第七步:修改Hello.java
public class Hello {
  public static void main(String[] args){
    System.out.println("CCC");
  }
}

第八步:编译Hello.java

第九步:使用java命令运行Hello类,发现打印结果是:AAA

说明Hello这个类是被启动类加载器找到的,找到以后就不查找其他位置了

第十步:删除$JAVA_HOME/jre/classes目录

第十一步:使用java命令运行Hello类,发现打印结果是:BBB

说明Hello这个类是被扩展类加载器找到的,找到以后就不查找其他位置了

第十二步:删除$JAVA_HOME/jre/lib/ext/classes目录

第十三步:使用java命令运行Hello类,发现打印结果是:CCC

说明Hello这个类是被应用程序类加载器找到的

(2)实验2

第一步:创建假的String类

package java.lang;
public class String {
    public String() {
        System.out.println("嘿嘿,其实我是假的!");
    }
}
  • 第一步:编写测试程序类
    @Test
    public void testLoadString() {
        // 目标:测试不同范围内全类名相同的两个类JVM如何加装
        // 1.创建String对象
        java.lang.String testInstance = new java.lang.String();
        // 2.获取String对象的类加载器
        ClassLoader classLoader = testInstance.getClass().getClassLoader();
        System.out.println(classLoader);
    }
  • 第三步:查看运行结果是null
  • 假的String类并没有被创建对象,由于双亲委派机制,启动类加载器加载了真正的String类.

2.3 小结

双亲委派机制的好处:

  • 避免类的重复加载:父加载器加载了一个类,就不必让子加载器再去查找了。同时也保证了在整个JVM范围内全类名是类的唯一标识。
  • 安全机制:避免恶意替换JRE定义的核心API(沙箱安全机制)。
相关文章
|
29天前
|
存储 缓存 Java
金石原创 |【JVM盲点补漏系列】「并发编程的难题和挑战」深入理解JMM及JVM内存模型知识体系机制(1)
金石原创 |【JVM盲点补漏系列】「并发编程的难题和挑战」深入理解JMM及JVM内存模型知识体系机制(1)
37 1
|
2月前
|
Oracle Java 编译器
基本概念【入门、 发展简史、核心优势、各版本的含义、特性和优势、JVM、JRE 和 JDK 】(二)-全面详解(学习总结---从入门到深化)
基本概念【入门、 发展简史、核心优势、各版本的含义、特性和优势、JVM、JRE 和 JDK 】(二)-全面详解(学习总结---从入门到深化)
47 1
|
1天前
|
前端开发 Java 开发者
JVM类加载器的分类以及双亲委派机制
JVM类加载器的分类以及双亲委派机制
|
11天前
|
监控 Java 关系型数据库
JVM工作原理与实战(十三):打破双亲委派机制-线程上下文类加载器
JVM作为Java程序的运行环境,其负责解释和执行字节码,管理内存,确保安全,支持多线程和提供性能监控工具,以及确保程序的跨平台运行。本文主要介绍了打破双亲委派机制的方法、线程上下文类加载器等内容。
14 2
|
1月前
|
前端开发 Java
深入理解Java虚拟机:类加载机制
【2月更文挑战第23天】本文深入探讨了Java虚拟机(JVM)的类加载机制,包括类加载器的层次结构、类加载的过程以及双亲委派模型。通过对JVM类加载机制的理解,可以帮助我们编写更高效的Java代码。
|
1月前
|
安全 前端开发 Java
【JVM】双亲委派机制详细解读(通俗易懂)
【JVM】双亲委派机制详细解读(通俗易懂)
111 0
|
2月前
|
安全 Java 应用服务中间件
|
3月前
|
Oracle IDE Java
基本概念【入门、 发展简史、核心优势、各版本的含义、特性和优势、JVM、JRE 和 JDK 】(二)-全面详解(学习总结---从入门到深化)(下)
基本概念【入门、 发展简史、核心优势、各版本的含义、特性和优势、JVM、JRE 和 JDK 】(二)-全面详解(学习总结---从入门到深化)
37 1
|
3月前
|
Java 程序员 PHP
基本概念【入门、 发展简史、核心优势、各版本的含义、特性和优势、JVM、JRE 和 JDK 】(二)-全面详解(学习总结---从入门到深化)(上)
基本概念【入门、 发展简史、核心优势、各版本的含义、特性和优势、JVM、JRE 和 JDK 】(二)-全面详解(学习总结---从入门到深化)
32 0
|
3月前
|
缓存 安全 前端开发
JVM(类的加载与ClassLoader、双亲委派机制)
JVM(类的加载与ClassLoader、双亲委派机制)