Java基础JVM之简介<一>

126 阅读5分钟

JVM 的运行机制学习

image.png

Java基础JVM之简介<一>

Java基础JVM之类加载器<二>

Java基础JVM之运行时内存<三>

Java基础JVM之执行引擎<四>

Java基础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 结构

图片借用的(我不会画)..... image.png

  • 类加载器

    类加载器是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++ 编写)
  • 本地方法接口/本地方法库

    就是用 C/C++ 或汇编 写的库文件(.dll.so.dylib),被 JVM 通过 JNI(Java Native Interface,本地方法接口) 调用

  • 程序计数器

当前线程所执行的字节码指令的地址(行号),指向下一条要执行的指令的指针”

       ┌──────────────────────┐
       │   JVM 运行时数据区     │
       ├──────────────────────┤
       │ 程序计数器 (PC寄存器) │ ← 记录下一条指令地址
       │ Java虚拟机栈         │ ← 方法调用、局部变量
       │ 本地方法栈           │ ← native 方法调用
       │ 堆 (Heap)            │ ← 对象实例
       │ 方法区/元空间        │ ← 类信息、常量池
       └──────────────────────┘

4.JVM 调用和执行流程

  • 编译期

    • import 只是告诉编译器类的全名,生成字节码里的符号引用。
  • 类加载

    • Demo.classArrayList.classString.class 由类加载器加载进 方法区/元空间
  • 运行期

    • 创建 list → 在 分配内存,引用放入 栈帧局部变量表
    • list.add("Hello JVM") → 操作数压入 栈帧操作数栈,调用 ArrayList.add 方法。
    • System.out.println(list.get(0)) → 调用本地方法库,通过 本地方法栈 输出字符串。
  • 执行控制

    • 程序计数器 (PC) 指示当前字节码位置,执行引擎(解释器或 JIT)逐条执行。
  • 方法返回与销毁

    • 方法执行完 → 栈帧出栈 → 堆里的对象如果无引用 → GC 回收。
    • JVM 进程退出 → 方法区、堆、栈、PC 寄存器等全部内存释放。
源码(.java)
   │
   ▼
编译(javac)
   │   import 仅在此时解析全限定类名
   ▼
字节码(.class)
   │
   ▼
类加载器 → 加载类
   │
   ▼
链接 → 验证 → 准备 → 解析
   │
   ▼
初始化(静态代码块、静态变量)
   │
   ▼
执行引擎(解释/编译)
   │
   ▼
运行时数据区协作
   │
   ▼
程序结束 → GC 回收 → 类卸载

执行要点

  1. JVM 启动 → 创建运行时内存空间
  2. 类加载器加载类 → 方法区 / 元空间存储类信息
  3. 执行引擎执行方法 → 栈帧存方法调用,堆存对象
  4. 方法返回 → 栈帧销毁 → GC 回收堆对象
JVM 启动
    │
    ▼
创建运行时内存空间
    ├─ 方法区 / 元空间
    ├─ 堆
    ├─ 栈
    ├─ 程序计数器
    └─ 本地方法栈
    │
    ▼
类加载器加载类 → 方法区 / 元空间
    │
    ▼
执行引擎执行方法
    ├─ 栈帧入栈(局部变量、操作数栈)
    ├─ 对象在堆分配
    └─ 调用本地方法栈
    │
    ▼
方法返回 → 栈帧出栈 → 对象可回收 → JVM 退出释放内存

总结

JVM知识简单梳理为,后续JAVA基础的梳理做准备