了解JVM(Java虚拟机)首先我们必须了解VM(虚拟机)是什么。
所谓虚拟机(Virtual Machine),就是一台虚拟的计算机。它是一款软件,用来执行一系列虚拟计算机指令。大体上,虚拟机可以分为系统虚拟机和程序虚拟机。
我们经常见到的 VMware 就属于系统虚拟机,它是完全对物理计算机的仿真,提供了一个可运行完整操作系统的软件平台。
程序虚拟机典型的代表就是 Java 虚拟机了,它专门为执行某个单个计算机程序而设计。在 Java 虚拟机中执行的指令我们称为 Java 字节码指令。无论是系统虚拟机还是程序虚拟机,在上面运行的软件都被限制于虚拟机提供的资源。Java 虚拟机是一种执行 Java 字节码文件的虚拟计算机,它拥有独立的运行机制。
Java 技术的核心就是 Java 虚拟机,因为所有的 Java 程序都运行在 Java 虚拟机内部。
JVM概述
JVM就是Java虚拟机,虚拟机就是一台虚拟的计算机,是一款软件。Java 虚拟机就是二进制字节码的运行环境,负责装载字节码到其内部,解释或编译为对应平台上的机器码指令执行,每一条 Java 指令,Java 虚拟机中都有详细定义,如怎么取操作数,怎么处理操作数,处理结果放在哪儿等。JVM是运行在操作系统上的,不与硬件直接交互。
JVM整体的四个部分
JVM整体组成可以分为4个部分:
1.类加载器(ClassLoader)
2.运行时数据区(Runtime Data Area)
3.执行引擎(Execution Engine)
4.本地方法接口(Native Interface)
程序在执行之前先要把 Java 代码转换成字节码(.class 文件),JVM 首先需要把字节码通过一定的类加载器(Class Loader)把文件加载到内存中运行时数据区(Runtime Data Area),而字节码文件是 JVM 的一套指令集规范,并不能直接交给底层操作系统去执行,因此需要特定的命令解析器(执行引擎(Execution Engine)) 将字节码翻译成底层系统指令再交由 CPU 去执行,而这个过程中需要调用其他语言的接口(本地方法接口(Native Interface)) 来实现。整个程序的功能,这就是这 4 个主要组成部分的职责与功能。
1.1 类加载器
Java编译器会为虚拟机转换源指令。虚拟机代码存储在以 .class 为扩展名的类文件中,每个类文件都包含某个类或者接口的定义和实现代码。 ——Java核心基础(卷二)
1.1.1 类加载器过程
类加载器子系统负责从文件系统或者网络中加载 class 文件, class 文件在文件开头有特定的文件标识(字节码文件都以 CA FE BA BE 标识开头)。classLoader 只负责 class 文件的加载,至于它是否可以运行,则由执行引擎决定。加载的类信息存放于一块称为方法区的内存空间。除了类的信息外,方法区中还会存放运行时常量池信息,可能还包括字符串字面量和数字常量(这部分常量信息是 class 文件中常量池部分的内存映射)。
类加载的过程
1.加载过程是把class文件(字节码文件)加载到内存中(I/O读写)。类加载器把文件加载到内存中,会为每个类创建一个Class类的对象,调用Class类中的方法获取类的相关信息。
2.验证是检验加载的类是否有正确的内部结构并和其他类协调一致。
3.准备阶段为类的静态属性分配内存,并设置默认初始值(不包含final修饰的static常量),也不会给实例变量初始化。
4.解析是将二进制数据中的符号引用替换成直接引用(符号引用是用一组符号描述所引用的目标;直接引用是指向目标的指针)。
5.类初始化
5.1 什么时候初始化类
1 )创建类的实例,也就是 new 一个对象
2)访问某个类或接口的静态变量,或者对该静态变量赋值
3)调用类的静态方法
4)反射
5)初始化一个类的子类(会首先初始化子类的父类)
5.2 类的初始化顺序:
父类static --> 子类static --> 父类构造方法 --> 子类构造方法
1.1.2类加载器的分类
1.1.2.1启动类加载器(引导类加载器)
是由c/c++实现,用来加载Java的核心类库
1.1.2.2扩展类加载器
由Java实现,派生于 ClassLoader 类。上层类加载器是引导类加载器(启动类加载器),加载底层类库
1.1.2.3应用程序类加载器
Java实现,派生于 ClassLoader 类。上层类加载器是扩展类加载器,加载自定义类。
1.1.3 双亲委派机制
加载类时,向上委派,交给最上层的加载器启动类加载器加载核心类库,加载不到就用扩展类加载器加载底层类库,加载不到就用应用程序类加载器加载自定义类
双亲委派机制的优点
1.安全,可避免用户自己编写的类动态替换 Java 的核心类(自定义的类名和Java核心类名相同)
2.避免全限定命名的类重复加载(使用了 findLoadClass()判断当前类是否已加载)
1.1.4沙箱安全机制
作用是防止恶意代码污染 Java 源代码
如果一个类在引导类加载器那里就加载到了,先找到先使用,所以就使用引导类加载器里面的类,后面的一概不能使用,这就保证了不被恶意代码污染。
1.1.5 类的主动使用和被动使用
JVM 规定,每个类或者接口被首次主动使用时才对其进行初始化,有主动使用,自然就有被动使用。
主动使用:
1.通过new关键字被导致类的初始化,这是大家经常使用的初始化一个类的方式,
他肯定会导致类的加载并且初始化
2.访问类的静态变量,包括读取和更新
3.访问类的静态方法
4.对某个类进行反射操作,会导致类的初始化
5.初始化子类会导致父类的的初始化
6.执行该类的 main 函数
被动使用:其实除了上面的几种主动使用其余就是被动使用了
注意:主动使用和被动使用的区别在于类是否会被初始化.
1.引用该类的静态常量,注意是常量,不会导致初始化,但是也有意外,这里的常量是指已经指定字面量的常量,对于那些需要一些计算才能得出结果的常量就会导致初始化,比如:
public final static int number = 5 ; //不会导致类初始化,被动使用
public final static int random = new Random().nextInt() ; //会导致类的初始化,主动使用
2.构造某个类的数组时不会导致该类的初始化,比如:
Student[] students = new Student[10] ;