Java—JVM

简介: Java—JVM

JVM


JDK / JRE / JVM 的关系

JDK 开发工具包

(java development kit) 支持开发和运行 Java 程序。

JDK 包含 JRE 以及各种 Java 开发工具(如编译器 javac 、调试器 jdb 等)。

JRE 运行环境

(java runtime environment) 能够运行已编译的 Java 程序。

JRE 包含 JVM 以及运行时所需调用的基础类库(如 java.lang 包、 java.util 包等)。

JVM 虚拟机

(java virtual machine) 运行 Java 程序的工作环境。

Java 程序在虚拟机上运行而不是直接在操作系统上运行,从软件层面屏蔽了底层硬件指令的细节。虚拟机会根据操作系统自动将字节码文件转化成相应的机器码,使 Java 字节码文件能够在多种平台上不加修改地运行。

HotSpot 虚拟机 是 SunJDK 和 OpenJDK 中所带的虚拟机,也是目前使用范围最广的 Java 虚拟机。


Java 运行原理

基本概念

解释和编译

  • 解释:源文件经过编译器编译成为脚本文件,由解释器逐行解释并执行。灵活性更好。
  • 编译:源文件经过编译器编译成为可执行文件,由计算机直接去执行。性能更好。

静态编译和动态编译

  • 静态编译:编译时确定类型,绑定对象。性能更好。
  • 动态编译:运行时确定类型,绑定对象。能更好地支持多态,灵活性强。

Java 运行原理

Java 是编译和解释并行的语言,采取动态编译,支持反射机制。

  1. 源文件(.java) 经过编译器编译成为 字节码文件(.class) ,通过类加载器搬运到 JVM 中逐行解释并执行。
  2. 即时编译器(JIT) 在编译时会识别反复执行的热点代码(超过 10000 次)并保存机器码,复用时可直接由 JVM 执行。

优势:以虚拟机作为中介,字节码文件可以在所有操作平台上通用。即一次编译、到处运行。

劣势:但这也导致了 Java 语言性能不如 C/C++ 等编译语言。


类加载

在 Java 程序里如果使用某个尚未加载到内存中的类,JVM 会通过加载、链接、初始化 3 个步骤来对该类进行初始化。

!类

创建类的实例,访问类的静态变量,或者调用类的静态方法都会导致类的初始化。但要注意对于 final 常量,如果在编译时就可以确定该变量的值,编译器会在编译时直接把这个变量替换成它的值,因此即使程序使用该静态变量,也不会导致该类的初始化。

加载

类的加载由类加载器完成。类加载器会读取类的字节码文件,并为之创建一个 java.lang.Class 对象。

类加载器使用双亲委派模型,类加载器具备一种带有优先级的层次关系:

  • 根类加载器:负责加载 Java 的核心类,原生代码实现,并不继承自 java.lang.ClassLoader 类。
  • 扩展类加载器:负责加载 JRE 扩展目录中的类。由 Java 语言实现,没有父类加载器。
  • 系统类加载器:负责加载 CLASSPATH 路径中的类。由 Java 语言实现,父类加载器为扩展类加载器。
  • 用户类加载器:开发者通过继承 ClassLoader 基类来创建的类加载器。由 Java 语言实现,默认父类加载器为系统类加载器。

任何类加载器在接到加载类的请求时,都会将加载任务委托给父类加载器,最终委派给处于模型最顶端的根类加载器进行加载。只有父类加载器无法完成此加载任务时,才自己去加载。如果均无法载入类,则抛出 ClassNotFountException 异常。

  1. 通过这种层级关系可以避免类的重复加载。
  2. 其次可以防止核心 API 库被随意篡改,用户即使编写了 java.lang.Object 的同名类,也永远无法被加载运行。

【在双亲委派模型中,由父加载类加载的类,下层加载器是不能加载的。用户在 classpath 路径下自定义的java.*包内的类会抛出异常:SecurityException: Prohibited package name】

链接

当类被加载并生成 Class 对象后,连接阶段负责把类的二进制数据合并到 JRE 中。

  • 验证:验证阶段用于检验被加载的类是否有正确的内部结构,并和其他类协调一致。
  • 准备:类准备阶段负责为类的静态变量分配内存,并赋予类型的默认值。
  • 解析:将类的二进制数据中的符号引用替换成直接引用,指向具体的内存空间。

Java 是相对 C++ 语言是安全的语言,验证过程用于确保 Class 文件的字节流符合当前虚拟机要求,不会危害虚拟机自身安全。其主要包括四种验证,文件格式验证,元数据验证,字节码验证,符号引用验证。

初始化

为类的静态变量赋予程序设定的初始值。



目录
相关文章
|
6天前
|
存储 Java
深入理解Java虚拟机:JVM内存模型
【4月更文挑战第30天】本文将详细解析Java虚拟机(JVM)的内存模型,包括堆、栈、方法区等部分,并探讨它们在Java程序运行过程中的作用。通过对JVM内存模型的深入理解,可以帮助我们更好地编写高效的Java代码,避免内存溢出等问题。
|
1天前
|
消息中间件 Java Linux
2024年最全BATJ真题突击:Java基础+JVM+分布式高并发+网络编程+Linux(1),2024年最新意外的惊喜
2024年最全BATJ真题突击:Java基础+JVM+分布式高并发+网络编程+Linux(1),2024年最新意外的惊喜
|
1天前
|
算法 Java 编译器
从Java字节码到JIT编译器,深入理解Java虚拟机
Java虚拟机(JVM)是Java程序运行的关键。想深入理解Java虚拟机,我们需要了解Java字节码、类加载机制、垃圾回收算法、JIT编译器等方面的知识。本文将介绍这些关键知识点,并通过示例代码加深理解。
|
5天前
|
Java 数据库连接 Spring
K8S+Docker理论与实践深度集成java面试jvm原理
K8S+Docker理论与实践深度集成java面试jvm原理
|
6天前
|
Java 索引
深入浅出JVM(五)之Java中方法调用
深入浅出JVM(五)之Java中方法调用
|
6天前
|
Java 编译器 对象存储
java一分钟之Java入门:认识JDK与JVM
【5月更文挑战第7天】本文介绍了Java编程的基础——JDK和JVM。JDK是包含编译器、运行时环境、类库等的开发工具包,而JVM是Java平台的核心,负责执行字节码并实现跨平台运行。常见问题包括版本不匹配、环境变量配置错误、内存溢出和线程死锁。解决办法包括选择合适JDK版本、正确配置环境变量、调整JVM内存参数和避免线程死锁。通过代码示例展示了JVM内存管理和基本Java程序结构,帮助初学者更好地理解JDK和JVM在Java编程中的作用。
23 0
|
6天前
|
存储 监控 安全
JVM工作原理与实战(十六):运行时数据区-Java虚拟机栈
JVM作为Java程序的运行环境,其负责解释和执行字节码,管理内存,确保安全,支持多线程和提供性能监控工具,以及确保程序的跨平台运行。本文主要介绍了运行时数据区、Java虚拟机栈等内容。
12 0
|
6天前
|
存储 缓存 安全
【 Java中String源码分析(JVM视角你不来看看?】
【 Java中String源码分析(JVM视角你不来看看?】
16 0
|
6天前
|
存储 机器学习/深度学习 Java
【Java探索之旅】数组使用 初探JVM内存布局
【Java探索之旅】数组使用 初探JVM内存布局
29 0
|
6天前
|
小程序 Java 程序员
【Java探索之旅】我与Java的初相识(二):程序结构与运行关系和JDK,JRE,JVM的关系
【Java探索之旅】我与Java的初相识(二):程序结构与运行关系和JDK,JRE,JVM的关系
30 0