重点知识学习(4.1)--[jvm概述,类加载机制]

小智RE0      2022-04-21     720

关键词:

一:JVM(Java虚拟机)概述

前几天安装的VMware工具,它就是虚拟机

  • 所谓虚拟机(Virtual Machine),虚拟的计算机。作为一款软件,用来执行一系列虚拟计算机指令。大体上,虚拟机可以分为系统虚拟机和程序虚拟机
  • VMware 就属于系统虚拟机,它是对物理计算机的仿真,提供可运行完整操作系统的软件平台。程序虚拟机典型的代表就是 java 虚拟机了,为执行某个单个计算机程序而设计。
  • 在 java 虚拟机中执行的指令称为 java 字节码指令。
  • Java 虚拟机是执行 java 字节码文件的虚拟计算机,具有独立的运行机制。
  • Java 技术核心就是 java 虚拟机,所有 java 程序都运行在 java 虚拟机内部

JVM作用

Java 虚拟机就是二进制字节码的运行环境,负责装载字节码到其内部解释/编译执行到对应平台上的机器码指令,每条 java 指令,java 虚拟机中都有详细定义,如怎么取操作数,怎么处理操作数,处理结果放在哪儿。

JAVA虚拟机的特点
(1) 一次编译到处运行,可移植性高;
(2)作为跨语言平台,不仅可执行 java 字节码文件,还可执行其他语言编译后的字节码文件;
(3) 自动内存管理
(4) 自动垃圾回收功能

位置

运行在操作系统之上的,它与硬件没有直接的交互。

分类

  • 类加载器(ClassLoader)
  • 运行时数据区(Runtime Data Area)
  • 执行引擎(Execution Engine)
  • 本地库接口(Native Interface)

简略流程

一次编译,到处运行

通常所说的 JVM 组成指的是运行时数据区(Runtime DataArea),因为通常需要程序员调试分析的区域就是“运行时数据区”,或者“运行时数据区”里面的 Heap(堆)模块。

程序在执行之前先要把 java 代码转换成字节码(class 文件),jvm 把字节码通过一定的方式 类加载器(ClassLoader) 把文件加载到内存中的运行时数据区(Runtime Data Area) ,而字节码文件是 jvm 的一套指令集规范,并不能直接交个底层操作系统去执行,因此需要特定的命令解析器执行引擎(Execution Engine) 将字节码翻译成底层系统指令再交由CPU 去执行,而这个过程中需要调用其他语言的接口 本地库接口(NativeInterface) 来实现整个程序的功能.

  • JVM 主要任务就是负责将字节码装载到其内部,解释/编译为对应平台上的机器指令执行。JVM 使用类加载器(Class Loader)装载 class 文件。

  • 类加载完成后,会进行字节码校验,字节码校验通过之后 JVM 解释器会把字节码翻译成机器码交由操作系统执行。

  • 但不是所有的代码都是解释执行,JVM 对此作了优化,比如 HotSpot 虚拟机,自身提供JIT(Just In Time)编译器.


JVM的架构模型

Java 编译器输入的指令流基本上是一种基于栈的指令集架构,另一种指令集架构是基于寄存器的指令集架构.

区别:

  • 基于栈的指令集架构:
    • 无需硬件支持,可移植性好,能实现跨平台.
    • 设计和实现更简单,适用于资源受限的系统.
    • 使用零地址指令方式分配,其执行过程依赖于操作栈,指令集更小,编译器容易实现.
  • 基于寄存器式的指令集架构:
    • 指令完全依赖于硬件,可移植性差.
    • 性能优秀,执行更高效.
    • 完成操作时使用的指令更少

使用 javap -v class文件可以将 class 文件反编译为指令集. 所以由于跨平台的设计,Java 指令集都是根据栈来设计的,不同 CPU 架构不同, 所以不能设计为基于寄存器的. 优点是跨平台,指令集小,编译器容易实现. 缺点是性能下降,实现同样功能需要更多的指令.


二:JVM类加载[classLoader]

类加载子系统

首先看看之前的流程图中的类加载子系统;分为三个流程;
加载阶段:里面分类了不同的加载器
链接阶段:验证,准备,解析
初始化阶段:

作用:

  • 类加载器子系统负责从文件系统或者网络中加载 class 文件。

  • 主要负责加载类, 有执行引擎执行,存放在方法区(元空间)

  • class文件存在于硬盘上,可理解为模板,而最终这个模板在执行的时会被加载到 JVM 里,根据此模板实例化出 n 个一模一样的实例

  • class 文件 加载到 JVM 中,被称为 DNA 元数据模板,放在方法区中.

加载过程之–>加载阶段

  • 根据类的地址,从硬盘上读取类的信息,

  • 将信息读入到方法区,生成Class类的对象

加载过程之–>链接阶段

  • (1) 验证: 验证字节码文件格式是否是当前虚拟机所支持的文件格式,语法格式;
    • 验证文件格式是否一致: class 文件在文件开头有特定的文件标识(字节码文件都以 CA FE BA BE 标识开头);主,次版本号是否在当前 java 虚拟机接收范围内.
    • 元数据验证:对字节码描述的信息进行语义分析,以保证其描述的信息符合java 语言规范的要求,例如这个类是否有父类;是否继承浏览不允许被继承的类(final 修饰的类)…
      找到之前使用过的文件

命令运行;可输出

但是,若是在编译的Hello.class文件中放置一些其他信息;

这时就会被验证出错误

  • (2) 准备: 为静态成员分配默认值(int 默认值0) ;
  • 注意static final修饰的 静态常量在编译期间赋值

比如看这个案例

/**
 * @author by 信计1801 李智青 学号:1809064012
 */
public class Demo 

    //准备阶段时,为静态的变量进行初始化赋值; 默认值为0;初始化阶段时才赋值
    static int number = 10;
    //在编译期间直接赋值; 静态常量;
    static  final  int BAN = 100;

    //初始化触发;
    static 
        System.out.println("这是一行输出");
    

静态常量在编译期间之间赋值;这个类并没有被加载

但是要是访问静态变量的话;

  • (3) 解析: 将字节码中符号引用 替换 成 直接引用; 类加载到内存后把符号的引用地址 换成 内存的地址引用
    符号引用: Class 文件的逻辑符号,直接引用指向的方法区中某一个地址​

加载过程之–>初始化阶段

类在什么情况下会初始化:

  • (1)创建类的实例,也就是 new 一个对象

  • (2)访问某个类或接口的静态变量,或者对该静态变量赋值

  • (3)调用类的静态方法 ,静态域

  • (4)反射(例如Class.forName(“”))

  • (5)初始化一个类的子类时;(就会首先初始化子类的父类)

初始化顺序
顺序是:父类 static –> 子类 static –> 父类构造方法- -> 子类构造方法

  • 先初始化静态的,多个静态的按照从上向下的顺序执行,

  • 如果类有父类,则先初始化父类的静态,然后是子类.

  • 如果是创建对象,先调用父类的构造方法,然后是子类自己的构造方法


类加载器

按照JVM 分类 :类加载器可以分为两种

  • 引导类加载器(启动类加载器 Bootstrap ClassLoader).
  • 其他所有类加载器,由 java 语言实现,独立存在于虚拟机外部,继承自抽象类java.lang.ClassLoader.

java 开发分类:

(1)引导类加载器(启动类加载器 BootStrap ClassLoader)

  • 使用 C/C++语言实现,嵌套在 JVM 内部;用来加载 java 核心类库;负责加载扩展类加载器和应用类加载器;且指定父类加载器;
  • 它不继承自 java.lang.ClassLoader; 且没有父加载器.
  • 引用类加载器只加载存放在<JAVA_HOME>\lib目录,或者被-Xbootclasspath 参数锁指定的路径中存储放的类;

(2)扩展类加载器(Extension ClassLoader)

  • Java语言编写;程序中默认的类加载器; sun.misc.Launcher$ExtClassLoader实现;继承自ClassLoader 类;

  • java.ext.dirs 系统属性所指定的目录中加载类库,或从 JDK 系统安装目录的jre/lib/ext 子目录(扩展目录)下加载类库.当我们创建的 jar 放在此目录下,也会自动由扩展类加载器加载.

(3)应用程序类加载器(系统类加载器 Application ClassLoader)

  • sun.misc.Launcher$AppClassLoader 实现; Java语言编写,继承自ClassLoader类;

  • 用于加载用户类路径(classpath)上所有的类( 加载自定义的类)

ClassLoader 类,作为抽象类,其后所有的类加载器都继承自 ClassLoader(注意:不包括启动类加载器

案例

/**
 * @author by 信计1801 李智青 学号:1809064012
 */
public class ClassLoaderTest 
    public static void main(String[] args) 
        //应用程序类加载器
        ClassLoader sysClassLoader = ClassLoader.getSystemClassLoader();
        System.out.println(sysClassLoader);
        //sun.misc.Launcher$AppClassLoader@18b4aac2

        //获取 扩展类加载器;
        ClassLoader p1 = sysClassLoader.getParent();
        System.out.println(p1);
        //sun.misc.Launcher$ExtClassLoader@1b6d3586

        //继续向上获取;
        ClassLoader p2 = p1.getParent();
        System.out.println(p2);
        //null

        //我这里自定义的类,用的是应用程序类加载器;
        ClassLoader myLoader =ClassLoaderTest.class.getClassLoader();
        System.out.println(myLoader);
        //sun.misc.Launcher$AppClassLoader@18b4aac2

        //那么系统类库的类加载器就是 启动类加载器;
        ClassLoader l = Integer.class.getClassLoader();
        System.out.println(l);
        //null;
    


双亲委派机制浅入

  • 类加载时按需加载,使用时才会加载;当需要时才会将它的 class 文件加载到内存中生成class 对象

  • 类加载时,加载器都会将类交给父级类加载器加载.

  • 如果一个类加载器收到了类加载请求,它并不会自己先去加载,而是把这个请求委托给父类的加载器去执行,若它的父类还有父加载器;就一级一级的委派.

  • 若最终找到的类加载器无法完成任务;那么就在它向子类加载器中查找;最后如果还找不到,就抛出异常ClassNotFoundException

它的优点

  • 安全,可避免用户自己编写的类动态替换 Java 的核心类,比如 java.lang.String
  • 避免全限定命名的类重复加载(使用了 findLoadClass()判断当前类是否已加载)

例如,自定义String类

package java.lang;
/**
 * @author by 信计1801 李智青 学号:1809064012
 */
public class String 

    public String() 
        System.out.println("自定义的String类型成功");
    

我在其他位置测试调用创建对象;
这里实际加载的是系统的String类;

类的主/被动使用

主动使用和被动使用的区别在于类是否会被初始化.

主动

  • 通过new关键字被导致类的初始化;
  • 在当前类中执行main 函数
  • 访问类的静态变量,包括读取/更新;以及访问类的静态方法;
  • 对类进行反射操作
  • 初始化子类会导致父类的的初始化

被动

  • 引用该类的静态常量,不会导致初始化;
    • 注意这里的常量是指已经指定字面量的常量,
    • 对于需要计算才能得出结果的常量或者说在构造方法中赋值的常量就会导致初始化;
  • 构造类的数组时不会导致该类的初始化

95%的技术面试必考的jvm知识点都在这,另附加分思路!

...共6个大方向:内存模型、类加载机制、GC垃圾回收是比较重点的内容。性能调优部分偏重实际应用,重点突出实践能力。编译器优化和执行模式部分偏重理论基础,主要掌握知识点。各个部分的内容如下:1>内存模型部分:程... 查看详情

jvm学习笔记——虚拟机类加载机制

概述虚拟机把描述符的数据从Class文件加载到内存,并对数据进行校验、转换解析和初始化,最终形成可以被虚拟机直接使用的Java类型,这就是虚拟机的类加载机制。类的生命周期类从被加载到虚拟机内存中开始࿰... 查看详情

深入理解类加载机制

...类加载机制原文链接http://hammer.coding.me/2016/10/26/jvm-1/ 概述本文是我在学习jvm类加载机制的时候对网上的一些资料的整理和总结,后文会给出具体的参考地址。这里参考了很多的资料,从中总结了一个大致的流程并且丰富了很... 查看详情

重点知识学习(4.3)--[jvm的执行引擎,垃圾回收概述](代码片段)

文章目录1.执行引擎2.垃圾回收初概述2.1垃圾标记阶段算法(1)引用计数算法(2)可达性分析算法(根搜索算法、追踪性垃圾收集)finalization机制1.执行引擎Java虚拟机的核心部分之一;jvm将字节码加载到内存中;注意:字节码并不能够直接运... 查看详情

java面试问题笔记——jvm

...中,但对只是深度要求较高.其中内存模型,类加载机制,GC是重点方面.性能调优部分更偏向应用,重点突出实践能力.编译器优化和执行模式部分偏向于理论基础,重点掌握知识点.需了解内存模型各部分作用,保存哪些数据.类加载双亲... 查看详情

(转)jvm类生命周期概述:加载时机与加载过程

原文地址:http://blog.csdn.net/justloveyou_/article/details/72466105 JVM类加载机制主要包括两个问题:类加载的时机与步骤 和 类加载的方式。本文主要阐述了第一个问题,关于类加载的方式等方面的内容,包括JVM预定义的类加... 查看详情

还没搞懂jvm吗?95%的技术面试必问知识点都在这,还怕面不过?

...共6个大方向:内存模型、类加载机制、GC垃圾回收是比较重点的内容。性能调优部分偏重实际应用,重点突出实践能力。编译器优化和执行模式部分偏重理论基础,主要掌握知识点。各个部分的内容如下:1>内存模型部分:程... 查看详情

jvm类加载机制

一、概述JVM把描述类的数据从class文件加载到内存,并对数据进行校验、转换解析和初始化,最终形成可以被虚拟机直接使用的java类型,这就是JVM的类加载机制二、类加载过程加载—(验证—准备—解析)(连接Linking... 查看详情

深入了解jvm——虚拟机类加载机制

...注明作者和出处,禁止商业性质转载。开源创造世界概述虚拟机的 查看详情

jvm知识点总结

...ff0c;其中,内存模型、类加载机制、GC垃圾回收是比较重点的内容。各个部分需要了解的知识点如 查看详情

jvm类加载机制

1、概述  虚拟机把描述类的数据从Class文件加载到内存,并对数据进行校验、转换解析和初始化,最终形成可以被虚拟机直接使用的Java类型,这就是虚拟机的类加载机制。2、类的加载时机  类从被加载到虚拟机内存中开始... 查看详情

tomcat学习笔记tomcat类加载机制

tomcat学习笔记(四)Tomcat类加载机制类加载机制jvm的类加载机制双亲委派机制双亲委派机制的作用tomcat类加载机制类加载机制java类(.java)->字节码文件(.class)->字节码文件需要被加载到jvm内存中(这个过... 查看详情

带你整理面试过程中关于jvm的类加载机制的相关知识

文章目录一、JVM的类加载阶段1.加载2.验证3.准备4.解析5.初始化二、类加载器三、双亲委派机制四、OSGI一、JVM的类加载阶段(1)一篇文章带你深入了解虚拟机类加载时机(2)一篇文章带你深入了解虚拟机类加载过... 查看详情

一夜搞懂|jvm类加载机制

...们光临寒舍:我的GIthub博客学习导图一.为什么要学习类加载机制?今天想跟大家唠嗑唠嗑Java的类加载机制,这是Java的一个很重要的创新点,曾经也是Java流行的重要原因之一。Oracle当初引入这个机制是为了满足JavaApplet开发的需... 查看详情

jvm学习---类加载子系统(代码片段)

类加载子系统内存结构概述简图详细图类加载器子系统类加载器子系统作用类加载器ClassLoader角色类加载过程概述加载阶段链接阶段验证(Verify)准备(Prepare)解析(Resolve)符号引用初始化阶段类的初始化时机clinit()1,2,3说明4... 查看详情

jvm类加载机制

概述虚拟机把描述类的数据从class文件加载到内存,并对数据进行校验,转换解析和初始化,最终形成可以被虚拟机直接使用的Java类型,这就是虚拟机的类加载机制。类的加载指的是将类的.class文件中的二进制数据读入到内存中... 查看详情

深入理解jvm:类加载机制

概述虚拟机把描述类的数据从Class文件加载到内存,并对数据进行校验、转换解析和初始化,最终形成可以被虚拟机直接使用的Java类型,这就是虚拟机的类加载机制。与那些在编译时需要进行链接工作的语言不同,在Java语言里... 查看详情

jvm进阶之双亲委派机制(代码片段)

双亲委派机制1.概述2.本质3.实现4.优点5.弊端6.注意细节7.破坏示例8.热替换1.概述如果一个类加载器在接收到加载类的请求时,它首先不会自己尝试去加载这个类,而是把这个请求任务委托给父加载器去完成。依次递归ÿ... 查看详情