JVM学习记录

最近想要复习一下Java的体系知识,所以记录了JVM的学习。

文章目录

1.编译

JVM中运行的是.class文件,那么如何将.java文件转换为.class文件呢,这一过程就叫做编译。那又是怎么编译的呢?

复制代码
源码文件 (HelloWorld.java)
        ↓ 执行javac命令
┌─────────────────────────────────────────┐
│       词法分析 (Lexical Analysis)        │
│ 源代码字符流 → 标记(Token)流              │
└─────────────────────────────────────────┘
    我的理解就是识别"单词",识别常量名、变量名、关键字等标识符,
因为Java的标识符是有规则的,首字符必须为字母、下划线。
那这个检查就是在这个阶段的
        ↓
┌─────────────────────────────────────────┐
│       语法分析 (Syntax Analysis)         │
│ 标记流 → 抽象语法树(AST)                 │
└─────────────────────────────────────────┘
	这个阶段就是识别语法,像英语一样,Java也有自己的语法,你不能
违背语法。
        ↓
┌─────────────────────────────────────────┐
│      语义分析 (Semantic Analysis)       │
│ 类型检查、符号解析、语法树标注           │
└─────────────────────────────────────────┘
	语义分析是检查代码的逻辑含义是否正确的过程。语法正确的代码不一定有意义,语义分析就是找出那些"通顺但不合理"的代码。
        ↓
┌─────────────────────────────────────────┐
│   注解处理 (Annotation Processing)      │
│ 处理编译时注解,生成新代码           │
└─────────────────────────────────────────┘
        ↓
┌─────────────────────────────────────────┐
│  语法树转换 (AST Transformations)       │
│ 去除语法糖、内联常量、优化等             │
└─────────────────────────────────────────┘
        ↓
┌─────────────────────────────────────────┐
│      生成字节码 (Bytecode Generation)    │
│ AST → 字节码指令                         │
└─────────────────────────────────────────┘
        ↓
┌─────────────────────────────────────────┐
│      字节码优化 (Bytecode Optimization)  │
│ 简化、压缩、优化字节码                   │
└─────────────────────────────────────────┘
        ↓
       .class 文件

2.运行

现在已经生成了.class文件,使用java命令可以对这个文件进行运行,那运行的机理又是怎样的呢?

2.1完整流程

复制代码
执行 java HelloWorld
    ↓
操作系统启动JVM进程
    ↓
JVM初始化(创建JVM实例)
    ↓
├─ 1. 类加载
│   ├─ 加载(Loading)
│   ├─ 链接(Linking)→ 验证、准备、解析
│   └─ 初始化(Initialization)
│
├─ 2. 运行时数据区
│   ├─ 方法区(Method Area)
│   ├─ 堆(Heap)
│   ├─ 虚拟机栈(Stack)
│   ├─ 程序计数器(PC Register)
│   └─ 本地方法栈(Native Stack)
│
├─ 3. 执行引擎
│   ├─ 解释器
│   ├─ JIT编译器
│   └─ 垃圾回收器
│
└─ 4. 本地库接口

2.2操作系统启动JVM进程

首先需要在操作系统上开辟一个进程,具体的执行如下:

复制代码
1. 解析命令:java是JRE的可执行程序
2. 创建进程:
   - 分配内存空间
   - 创建进程控制块(进程控制块(Process Control Block,简称PCB)就像是一个进程的"身份证"+"档案"+"病历"。PID就在这里面)
   - 设置初始堆栈(例如下面的命令)
 java -Xms512m           # 初始堆大小
     -Xmx1024m          # 最大堆大小
     -Xss256k           # 线程栈大小
     -cp .              # 类路径
     HelloWorld         # 主类
     arg1 arg2          # 命令行参数
3. 加载JVM:
   - 加载jvm.dll(Windows)或 libjvm.so(Linux)
   - 初始化JVM

2.3JVM初始化

JVM的初始化,首先会调用JNI方法创建一个JVM实例,然后才会实现JVM的初始化。

2.3.1类加载

JVM初始化后,就如何加载要class文件呢,这个过程被成为类加载。具体的流程如下:

复制代码
.class文件(硬盘上)
    ↓
[1. 寻找文件] → 在哪些地方找.class文件?
    ↓
[2. 读取字节] → 把.class文件读取到内存
    ↓
[3. 解析格式] → 解析成ClassFile结构
    ↓
[4. 创建Class对象] → 在堆中创建Class对象
    ↓
[5. 放入方法区] → 存储类的元信息
    ↓
准备好被使用!
  • 寻找文件

这里面体现如何寻找文件,会从以下四个加载器中加载,至于加载的机制被称为双亲委派机制。

复制代码
1. 启动类加载器 (Bootstrap ClassLoader)
   搜索路径: $JAVA_HOME/jre/lib/*.jar
   查找顺序: rt.jar → jsse.jar → jce.jar → ...

2. 扩展类加载器 (Extension ClassLoader)
   搜索路径: $JAVA_HOME/jre/lib/ext/*.jar
   加载: javax.xml, javax.swing, javax.crypto等扩展类

3. 应用程序类加载器 (Application ClassLoader)
   搜索路径: CLASSPATH环境变量 或 -cp参数指定的路径
   加载: 你自己的类,如com.example.MyClass

4. 自定义类加载器
   搜索路径: 自定义的任何地方

双亲委派机制如下:

复制代码
你要加载 com.example.MyClass
    ↓
应用类加载器收到请求
    ↓
"我先不加载,让我爸爸(扩展类加载器)试试"
    ↓
扩展类加载器收到请求
    ↓
"我也让我爸爸(启动类加载器)试试"
    ↓
启动类加载器收到请求
    ↓
1. 在rt.jar中找com/example/MyClass.class
2. 找不到!返回null
    ↓
扩展类加载器自己尝试
    ↓
1. 在ext/*.jar中找com/example/MyClass.class
2. 找不到!返回null
    ↓
应用类加载器自己尝试
    ↓
1. 在CLASSPATH中找com/example/MyClass.class
2. 找到!加载成功
相关推荐
heanyu2 分钟前
STM32学习 1 ----串口通讯--阻塞式收发+支持printf
stm32·嵌入式硬件·学习
東雪木13 分钟前
软件设计师考试复习——CPU 结构、流水线、存储体系(主存 / 辅存)
学习·软件设计师复习
m0_7505803014 分钟前
用Python生成艺术:分形与算法绘图
jvm·数据库·python
2301_8194143024 分钟前
Python入门:从零到一的第一个程序
jvm·数据库·python
2501_9181269126 分钟前
学习所有6502写游戏动作的语句
汇编·嵌入式硬件·学习·游戏·个人开发
夏日听雨眠29 分钟前
文件学习9
数据结构·学习·算法
野犬寒鸦30 分钟前
从零起步学习JVM|| 第二章:JVM基本组成及JVM内存区域详解
服务器·开发语言·后端·学习·面试·职场和发展
罗罗攀32 分钟前
PyTorch学习笔记|张量的线性代数运算
人工智能·pytorch·笔记·学习·线性代数
皙然32 分钟前
深度解析三色标记算法:JVM 并发 GC 的核心底层逻辑
java·jvm·算法
苦涩花开548639 分钟前
Kubernetes学习,记一些笔记
笔记·学习·kubernetes