JVM 的运行机制学习
Java基础JVM之本地方法接口/本地方法库程序计数器<六>
1.JVM简介
Java 虚拟机 是运行Java文件的虚拟机器.作用是将.java文件,编译后的.class文件转换成不同平台的可执行的文件.是Java语言 跨平台的核心.
Dalvik/Art 是Android定制版本的虚拟机
- Android 5.0 之前:Dalvik 解释 / JIT 执行 .dex
- Android 5.0 之后:ART 在安装时 AOT 编译 .dex → 本地机器码
- Android 7.0+:ART 混合 AOT + JIT
2.JVM 怎么执行的
JVM 加载代码逻辑
Java/Kotlin源码 --(编译器)--> .class字节码 --(dex转换)--> .dex --(打包)--> APK 安装到Android --(ART + 类加载器)--> 加载执行 --> 生成本地机器码运行
1: Android Studio 编译流程(Java/Kotlin 代码 → APK)
-
源代码 Java/Kotlin 代码 (
.java/.kt) -
编译器(javac / kotlinc) 将
.java/.kt编译成.class文件(字节码) -
Dex 转换 Android 使用 DEX(Dalvik Executable) 格式
.class→.dex文件 -
打包
.dex+ 资源文件 + 清单文件 → APK(可安装文件) -
签名 APK 需要签名才能安装到设备
2:Android 安装与执行流程
-
安装 APK
- 用户通过 APK 安装应用
- 系统将 APK 解包、注册应用
-
ART/Dalvik 虚拟机
- Android 上的 JVM 替代品:ART(Android Runtime)
- 类加载器(ClassLoader) :加载 APK 中的
.dex文件
-
执行
- ART 将 DEX 字节码 即时编译(JIT)/提前编译(AOT) 成本地机器码
- CPU 执行本地代码
-
运行时数据区
- 堆(对象)
- 栈(方法调用、局部变量)
- 方法区(类信息、静态变量)
3.JVM 结构
图片借用的(我不会画).....
-
类加载器类加载器是Jvm提供的一种类加载的机制. 类加载器负责将class文件加载到内存中,转化为可执行对象
-
启动类加载器(Bootstrap Class Loader) 又称跟加载器
C/C++ 代码实现, 负责加载 核心类库:
$JAVA_HOME/jre/lib/rt.jar(或模块化的java.base等) -
扩展类加载器 (Extension Class Loader )
由 Java 实现,负责加载
jre/lib/ext/目录下的类库,或者通过系统变量java.ext.dirs指定的路径。 -
程序类加载器 (Application Class Loader )
Java 实现 负责加载 classpath 下的类,也就是我们自己写的代码和依赖。
-
自定义加载器(处理业务需要加密等特殊的加载器)
继承
ClassLoader实现 ,应用场景:热部署、模块化插件、加密字节码加载等。
-
-
执行引擎
负责 将字节码(.class 文件)中的指令转化为底层机器指令 并执行, 类加载子系统 与 运行时数据区 的桥梁。
-
解释执行:逐条读取字节码指令,逐条翻译成机器码执行。
-
即时编译(JIT) :热点代码(执行频繁的部分)会被编译成本地机器码,提升性能。
-
垃圾回收支持:与 JVM 内存管理协作,释放不再使用的对象。
-
-
运行时数据区(JVM内存区域)- Heap 堆区 (
线程共享):存储对象实例和数组,是 GC 管理的主要区域 - Java Stack 栈区 (私有) :存储方法调用的栈帧,局部变量表、操作数栈、动态链接、方法返回地址
- Method Area 方法区 (
线程共享) :存储类信息、静态变量、常量池、JIT 编译后的代码 - Native Method Stack 本地方法栈区 (私有) :支持 JVM 调用本地方法(C/C++ 编写)
- Heap 堆区 (
-
本地方法接口/本地方法库
就是用 C/C++ 或汇编 写的库文件(
.dll、.so、.dylib),被 JVM 通过 JNI(Java Native Interface,本地方法接口) 调用 -
程序计数器
当前线程所执行的字节码指令的地址(行号),指向下一条要执行的指令的指针”
┌──────────────────────┐
│ JVM 运行时数据区 │
├──────────────────────┤
│ 程序计数器 (PC寄存器) │ ← 记录下一条指令地址
│ Java虚拟机栈 │ ← 方法调用、局部变量
│ 本地方法栈 │ ← native 方法调用
│ 堆 (Heap) │ ← 对象实例
│ 方法区/元空间 │ ← 类信息、常量池
└──────────────────────┘
4.JVM 调用和执行流程
-
编译期
import只是告诉编译器类的全名,生成字节码里的符号引用。
-
类加载
Demo.class、ArrayList.class、String.class由类加载器加载进 方法区/元空间。
-
运行期
- 创建
list→ 在 堆 分配内存,引用放入 栈帧局部变量表。 list.add("Hello JVM")→ 操作数压入 栈帧操作数栈,调用ArrayList.add方法。System.out.println(list.get(0))→ 调用本地方法库,通过 本地方法栈 输出字符串。
- 创建
-
执行控制
- 程序计数器 (PC) 指示当前字节码位置,执行引擎(解释器或 JIT)逐条执行。
-
方法返回与销毁
- 方法执行完 → 栈帧出栈 → 堆里的对象如果无引用 → GC 回收。
- JVM 进程退出 → 方法区、堆、栈、PC 寄存器等全部内存释放。
源码(.java)
│
▼
编译(javac)
│ import 仅在此时解析全限定类名
▼
字节码(.class)
│
▼
类加载器 → 加载类
│
▼
链接 → 验证 → 准备 → 解析
│
▼
初始化(静态代码块、静态变量)
│
▼
执行引擎(解释/编译)
│
▼
运行时数据区协作
│
▼
程序结束 → GC 回收 → 类卸载
执行要点
- JVM 启动 → 创建运行时内存空间
- 类加载器加载类 → 方法区 / 元空间存储类信息
- 执行引擎执行方法 → 栈帧存方法调用,堆存对象
- 方法返回 → 栈帧销毁 → GC 回收堆对象
JVM 启动
│
▼
创建运行时内存空间
├─ 方法区 / 元空间
├─ 堆
├─ 栈
├─ 程序计数器
└─ 本地方法栈
│
▼
类加载器加载类 → 方法区 / 元空间
│
▼
执行引擎执行方法
├─ 栈帧入栈(局部变量、操作数栈)
├─ 对象在堆分配
└─ 调用本地方法栈
│
▼
方法返回 → 栈帧出栈 → 对象可回收 → JVM 退出释放内存
总结
JVM知识简单梳理为,后续JAVA基础的梳理做准备