什么是 JVM?
1. JVM 是一种用于计算设备的规范,它是一个虚构出来的机器,是通过在实际的计算机上仿真模拟各种功能实现的。
2. JVM 包含一套字节码指令集,一组寄存器,一个栈,一个垃圾回收堆和一个存储方法域。
3. JVM 屏蔽了与具体操作系统平台相关的信息,使 Java 程序只需生成在 Java 虚拟机上运行的目标代码(字节码),就可以在多种平台上不加修改地运行。
JVM 在执行字节码时,实际上最终还是把字节码解释成具体平台上的机器指令执行。
jdk、jre、jvm 是什么关系?
1. JRE(Java Runtime Environment),也就是 Java 平台。所有的 Java 程序都要在 JRE 环境下才能运行。
2. JDK(Java Development Kit),是开发者用来编译、调试程序用的开发包。JDK 也是 JAVA 程序需要在 JRE 上运行。
3. JVM(Java Virtual Machine),是 JRE 的一部分。它是一个虚构出来的计算机,是通过在实际的计算机上仿真模拟各种计算机功能来实现的。
JVM 有自己完善的硬件架构,如处理器、堆栈、寄存器等,还具有相应的指令系统。
Java 语言最重要的特点就是跨平台运行。使用 JVM 就是为了支持与操作系统无关,实现跨平台。
JVM 原理
1. JVM 是 Java 的核心和基础,在 Java 编译器和 os 平台之间的虚拟处理器,可在上面执行字节码程序。
2. Java 编译器只要面向 JVM,生成 JVM 能理解的字节码文件。Java 源文件经编译成字节码程序,通过 jvm 将每条指令翻译成不同的机器码,通过特定平台运行。
一、类的加载过程
如果 JVM 想要执行这个 .class 文件,我们需要将其装进一个类加载器 中,它就像一个搬运工一样,会把所有的 .class 文件全部搬进 JVM 里面来。
重点知识:
- Java 文件经过编译后变成 .class 字节码文件。
- 字节码文件通过类加载器被搬运到 JVM 虚拟机中。
- 虚拟机主要的 5 大块:方法区,堆都为线程共享区域,有线程安全问题,栈和本地方法栈和计数器都是独享区域,不存在线程安全问题,而 JVM 的调优主要就是围绕堆,栈两大块进行。
1.1 类加载流程
类加载的过程包括了加载、验证、准备、解析、初始化五个阶段。在这五个阶段中,加载、验证、准备和初始化这四个阶段发生的顺序是确定的,而解析阶段则不一定,它在某些情况下可以在初始化阶段之后开始,这是为了支持 Java 语言的运行时绑定(也成为动态绑定或晚期绑定)。另外注意这里的几个阶段是按顺序开始,而不是按顺序进行或完成,因为这些阶段通常都是互相交叉地混合进行的,通常在一个阶段执行的过程中调用或激活另一个阶段。
- 加载,查找并加载类的二进制数据,在 Java 堆中也创建一个 java.lang.Class 类的对象
- 连接,连接又包含三块内容:验证、准备、初始化。
1. 验证,文件格式、元数据、字节码、符号引用验证;
2. 准备,为类的静态变量分配内存,并将其初始化为默认值;
3. 解析,把类中的符号引用转换为直接引用。
- 初始化,为类的静态变量赋予正确的初始值;
- 使用,new 出对象程序中使用;
- 卸载,执行垃圾回收。
1.2 类加载器
加载一个 Class 类的顺序也是有优先级的,类加载器从最底层开始往上的顺序是这样的:
- BootStrap ClassLoader:rt.jar
- Extention ClassLoader: 加载扩展的 jar 包
- App ClassLoader:指定的 classpath 下面的 jar 包
- Custom ClassLoader:自定义的类加载器
二、垃圾回收
2.1 如何确定对象已死
通常,判断一个对象是否被销毁有两种方法:
- 引用计数算法:为对象添加一个引用计数器,每当对象在一个地方被引用,则该计数器加 1;每当对象引用失效时,计数器减 1。但计数器为 0 的时候,就表示该对象没有被引用。
- 可达性分析算法:通过一系列被称之为GC Roots的根节点开始,沿着引用链进行搜索,凡是在引用链上的对象都不会被回收。
就像上图的那样,绿色部分的对象都在GC Roots的引用链上,就不会被垃圾回收器回收,灰色部分的对象没有在引用链上,自然就被判定为可回收对象。
2.2 垃圾回收算法
2.2.1 标记--清除算法
见名知义,标记--清除算法就是对无效的对象进行标记,然后清除。
2.2.2 标记--复制算法
标记--复制算法就是把 Java 堆分成两块,每次垃圾回收时只使用其中一块,然后把存活的对象全部移动到另一块区域。