1. JVM 概述
Java 虚拟机(Java Virtual Machine,JVM)是 Java 程序的运行基础,它是一个虚构出来的计算机,通过在实际的计算机上仿真模拟各种计算机功能来实现。JVM 使得 Java 程序能够实现 "一次编写,到处运行" 的特性,因为 Java 程序编译后生成的字节码文件(.class 文件)可以在任何安装了对应 JVM 的操作系统上运行。
2. JVM 架构
2.1 类加载子系统(Class Loading Subsystem)
- 功能 :负责加载字节码文件到 JVM 中。它会根据类的全限定名来查找并加载对应的字节码文件,将其转换为
java.lang.Class
对象,这个对象会被存储在方法区中。 - 加载过程 :
- 加载 :通过类的全限定名获取定义此类的二进制字节流,将这个字节流所代表的静态存储结构转化为方法区的运行时数据结构,在内存中生成一个代表这个类的
java.lang.Class
对象。 - 链接:包括验证(确保被加载类的正确性)、准备(为类的静态变量分配内存并设置默认初始值)和解析(将常量池内的符号引用转换为直接引用)三个阶段。
- 初始化 :执行类构造器
<clinit>()
方法,为类的静态变量赋予正确的初始值。
- 加载 :通过类的全限定名获取定义此类的二进制字节流,将这个字节流所代表的静态存储结构转化为方法区的运行时数据结构,在内存中生成一个代表这个类的
2.2 运行时数据区(Runtime Data Areas)
- 程序计数器(Program Counter Register):可以看作是当前线程所执行的字节码的行号指示器,每个线程都有一个独立的程序计数器,它是线程私有的。
- Java 虚拟机栈(Java Virtual Machine Stacks):也是线程私有的,它的生命周期与线程相同。每个方法在执行时都会创建一个栈帧,用于存储局部变量表、操作数栈、动态链接、方法出口等信息。方法的调用和返回对应着栈帧的入栈和出栈操作。
- 本地方法栈(Native Method Stacks):与 Java 虚拟机栈类似,不过它是为执行本地方法(使用 native 关键字修饰的方法)服务的。
- 堆(Heap):是 JVM 中最大的一块内存区域,被所有线程共享。它用于存储对象实例和数组,几乎所有的对象实例都在这里分配内存。堆是垃圾回收的主要区域,根据对象的存活时间和特性,堆又可以分为新生代、老年代等不同的区域。
- 方法区(Method Area):也是被所有线程共享的内存区域,用于存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据。在 JDK 1.8 及以后,方法区被元空间(Metaspace)所取代,元空间使用本地内存。
2.3 执行引擎(Execution Engine)
- 功能:负责执行字节码指令。它会将字节码解释或编译为机器码,然后在底层操作系统上执行。
- 执行方式 :
- 解释执行:逐条将字节码解释为机器码并执行,这种方式启动速度快,但执行效率相对较低。
- 编译执行:使用即时编译器(Just-In-Time Compiler,JIT)将热点代码(经常执行的代码)编译为机器码并缓存起来,下次执行时直接使用编译后的机器码,提高执行效率。
2.4 本地方法接口(Native Method Interface,JNI)
- 功能:JNI 是 JVM 提供的一种机制,允许 Java 代码调用本地(如 C、C++)方法,也允许本地代码调用 Java 方法。通过 JNI,可以利用本地代码的高性能和丰富的库资源。
3. 垃圾回收(Garbage Collection,GC)
- 概念:垃圾回收是 JVM 自动管理内存的一种机制,它会自动回收不再使用的对象所占用的内存空间,避免内存泄漏。
- 常见算法 :
- 标记 - 清除算法(Mark - Sweep):首先标记出所有需要回收的对象,然后统一回收所有被标记的对象。这种算法会产生内存碎片。
- 标记 - 整理算法(Mark - Compact):先标记出需要回收的对象,然后将存活的对象向一端移动,最后清理掉端边界以外的内存。这种算法可以解决内存碎片问题。
- 复制算法(Copying):将内存分为大小相等的两块,每次只使用其中一块。当这一块内存用完后,将存活的对象复制到另一块上,然后清理掉使用过的内存块。这种算法适用于对象存活率较低的场景,如新生代。
- 分代收集算法(Generational Collection):根据对象的存活时间将内存分为不同的代,如新生代和老年代。不同的代采用不同的垃圾回收算法,新生代使用复制算法,老年代使用标记 - 清除或标记 - 整理算法。
4. JVM 性能调优
- 目的:通过调整 JVM 的参数,优化内存使用和垃圾回收策略,提高 Java 程序的性能和稳定性。
- 常见调优参数 :
-Xms
和-Xmx
:分别用于设置堆的初始大小和最大大小。例如,-Xms512m -Xmx1024m
表示堆的初始大小为 512MB,最大大小为 1GB。-XX:NewRatio
:用于设置新生代和老年代的比例。例如,-XX:NewRatio=2
表示新生代和老年代的比例为 1:2。-XX:SurvivorRatio
:用于设置新生代中 Eden 区和 Survivor 区的比例。例如,-XX:SurvivorRatio=8
表示 Eden 区和一个 Survivor 区的比例为 8:1。