Java虚拟机

作者:zhangyunlong 发布时间: 2024-09-13 阅读量:7 评论数:0

Java虚拟机(JVM)是一个运行Java程序的虚拟环境, 它负责将字节码转换为机器码并执行.


JVM组成部分:

1. 类加载器子系统

  • 类加载器的定义

    • Java的类加载器是JVM中用于动态加载类文件的组件, 它将.class文件中的字节码加载到内存中, 并转换为Class对象供JVM执行.

  • 类加载器的作用

    • 动态加载类

      • 在运行时按需加载类, 而不是在编译时加载所有类

    • 隔离不同的类命名空间

      • 通过不同的类加载器, 可以隔离同名类, 避免冲突

    • 三种类加载器

      • 启动类加载器: JVM的一部分, JDK9之前由C++实现, 之后由Java实现

      • 扩展类加载器: Java实现, 独立于虚拟机, 主要加载系统变量指定的类库

      • 应用程序类加载器: Java实现, 主要负责加载用户类路径上的类库, 应用程序的默认加载器

    • 自定义类加载器

      • 通过继承ClassLoader类重写findClass方法, 可以自定义类加载器

      • 应用场景: 例如热部署的动态重载

  • 双亲委派模型

    • 工作流程

      • 当类加载器试图加载某个类时, 会先逐层向上委派给父类加载器去加载, 直到根类加载器. 当逐层都无法加载时, 才由当前类加载器自行加载

    • 为什么有双亲委派模式

      • 避免重复加载同一个类, 保障核心类库不被篡改

  • 类加载器的工作流程

    • 加载

      • 将字节码内容读取到内存中, 生成class对象

    • 校验

      • 验证加载进来字节码内容的是否符合规范

    • 准备

      • 为静态变量赋初始值(注意, 是初始值, 例如int的初始值为0), 为静态变量在方法区划分内存空间

    • 解析

      • 将常量池的符号引用转为直接引用(例如: 让A做xxx, 变成让小明买菜)

    • 初始化

      • 执行一些静态代码块, 为静态变量赋值(注意, 这里才是真正的代码中赋值)

2. 运行时数据区(JVM内存模型)

  • 方法区

    • 存储类信息, 常量, 静态变量

    • 属于线程共享区域, 所有线程共享方法区内存

    • JDK8之前使用永久代来实现方法区, 从JDK8开始被元空间取代(元空间使用本地内存), 相当于更换接口的实现类(方法区接口由永久代实现改为元空间实现)

    • 用于存放所有线程共享的对象和数组, 是GC的主要区域

    • 新生代

      • 新生代存在一个Eden区和两个交替使用的Survivor区(S0和S1)

      • 新对象会被分配到Eden区, Eden区较大, 且GC频繁

      • 新对象在Eden区经过一次GC后存放到其中一个Survivor区, 年龄+1

      • 当Survivor区的对象年龄达到阀值(默认15)时, 会晋升到老年代

      • 年龄最大限制15的原因: 年龄信息存储在对象头中, 大小4位, 二进制最大值为1111, 对应10进制的15

    • 老年代

      • Major GC / Full GC 会在老年代进行, 但频率较低

    • 永久代 / 元空间

      • 永久代GC复杂, 且GC效率低

      • 从JDK8开始, 永久代被元空间取代, 直接使用本地内存

  • 虚拟机栈

    • 虚拟机按照先进后出的方式存储所有非本地方法调用的栈帧

    • 每个线程创建一个栈帧, 栈帧是线程私有的, 生命周期与线程相同

    • 栈帧中存储局部变量(存储基本数据类型以及对象引用, 如int ,float等), 操作次数栈, 动态链接, 方法返回地址等

    • 递归调用时可能导致压栈太深而溢出, 若虚拟机无法动态扩展或者申请到足够内存, 会报内存不足

  • 本地方法栈

    • 结构与虚拟机栈一致, 且线程私有

    • 为本地方法服务, 使用JNI调用的本地代码在此区域分配内存

    • 在HotSpot虚拟机中, 虚拟机栈和本地方法栈已合并

  • 程序计数器

    • 一个小的内存区域, 保存当前线程执行的字节码指令的地址和行号

    • 每个线程都有一个独立的计数器, 属于线程私有

    • 唯一不会出现OOM的区域

3. 执行引擎

  • 执行引擎的定义

    • 执行引擎将字节码转换为机器码并执行

  • 执行引擎的组成

    • 解释器

      • 逐行解释字节码并执行, 适用于程序初次运行

    • 即时编译器JIT

      • 将热点代码编译为机器码并缓存, 提升执行效率

    • 垃圾回收器

      • 自动回收堆内存中不再使用的对象, 是JVM内存管理的核心

4. 本地方法接口(JNI)

  • 本地方法接口

    • 提供了一个桥梁, 用于调用C/C++等语言编写的本地库

  • 本地方法库

    • 本地库的实现, 是JVM实现某些底层功能(线程操作, 网络通信等)的基础


扩展-直接内存与本地内存

特性

直接内存

本地内存

包含关系

属于本地内存的一部分

包含直接内存, 线程栈, 元空间等

主要用途

高性能NIO缓冲区, 减少数据复制

JVM运行自身所需的一切堆外内存

JVM限制

可通过-XX:MaxDirectMemorySize严格限制

受进程总内存限制, JVM自身无统一限制

GC影响

释放依赖于GC

GC无法直接回收, 只能回收其包含的直接内存和元空间部分

OOM错误

OutOfMemorry : Direct buffer memorry

各种Natice OOM, 或因线程数过多导致的进程崩溃

评论