Gio*_*dze 0 c++ java assembly processor virtual-machine
我试图围绕 Java 虚拟机以及它为什么使用字节码。我知道它被问了很多次,但不知何故我最终无法做出正确的假设,所以我研究了很多东西并决定解释我认为它是如何工作的以及它是否正确。
我知道在 C++ 中,编译器在特定(架构 + 操作系统)上编译源代码。因此,(x86 + Windows)的 C++ 编译版本不会在任何其他架构或操作系统上运行。
Java 编译器在将源代码编译为字节码时,并不根据体系结构或操作系统进行编译。如果在 Windows 或 Mac 上编译,源代码将始终编译为相同的字节码。假设我们编译了,现在将字节码发送到另一台计算机(x86 + windows)。为了让那台计算机运行这个字节码,它需要 JVM。现在,JVM 知道它在什么架构 + 操作系统上运行。(x86 + 窗户)。因此,JVM 会将字节码编译为 x86 + Windows,并生成现在可以由实际计算机运行的机器码。
因此,即使我们使用 Java 虚拟机,我们仍然在我们的操作系统上而不是在虚拟机上运行实际的机器代码。虚拟机只是帮助我们将字节码转换为机器码。
这意味着在使用 Java 时,我们唯一需要担心的是安装 JVM,仅此而已。
我一直认为虚拟机只是一台计算机本身,它可以在自己的隔离位置运行代码,但是对于 JVM,我认为这是不正确的,因为我认为 JVM 生成的机器代码仍然必须是在我们拥有的实际操作系统上运行。
你认为我的假设正确吗?
编译java代码时,会创建java-bytecode。
这个字节码是平台无关的,可以由 JVM 运行。这意味着像Kotlin这样的其他编程语言也可以生成这个 java 字节码并以 JVM 为目标。
因此,您对每个平台的 java 字节码都相同是正确的。
然而,您不完全正确的地方是,JVM 将 java 字节码转换为本地字节码。
JVM 改为执行 java 字节码并将指令提供给操作系统。在执行时,JVM 将成束的 java 字节码编译为本机代码,然后操作系统可以执行这些代码。这发生在代码执行时,因此从未加载的类也将永远不会被执行,并且永远不会作为机器代码结束。
因此,我们可以使用反射之类的功能,其中类文件的某些 java 字节码可以在运行时修改,然后再编译为本地机器代码。
JVM 基本上位于操作系统和 java 字节码之间。在某种意义上就像一个普通的虚拟机。
下面的文章对 JVM 进行了很好的可视化。
https://www.guru99.com/java-virtual-machine-jvm.html
Java 编译器在将源代码编译为字节码时,并不根据体系结构或操作系统进行编译。如果在 Windows 或 Mac 上编译,源代码将始终编译为相同的字节码。
全都正确。
假设我们编译了,现在将字节码发送到另一台计算机(x86 + windows)。为了让那台计算机运行这个字节码,它需要 JVM。现在,JVM 知道它在什么架构 + 操作系统上运行。(x86 + 窗户)。因此,JVM 会将字节码编译为 x86 + windows,并生成现在可以由实际计算机运行的机器码。
这大部分是正确的,但有几件事有点“不合适”
首先,要在任何需要 JVM 的计算机上执行字节码。这包括编译字节码的计算机。
(理论上有可能将计算机设计和实现为执行 JVM 字节码指令集作为其本机指令集。但我不知道是否有人认真考虑过这样做。这毫无意义。性能不会和几百块钱就能买到的硬件相比。JVM字节码指令集设计紧凑简单,JIT编译相对容易,执行效率不高。)
其次,典型的 JVM 实际上以两种模式运行:
请注意,JIT 编译器是特定于平台的。
因此,即使我们使用 Java 虚拟机,我们仍然在我们的操作系统上而不是在虚拟机上运行实际的机器代码。
那是正确的。
[Java]虚拟机只是帮助我们将字节码转换为机器码。
JVM 实际上做得更多。像:
这意味着在使用 Java 时,我们唯一需要担心的是安装 JVM,仅此而已。
是的。但是在现代 JDK 中还有其他选择;egjlink将生成一个可执行文件,其中嵌入了一个精简的 JRE,这样您就不需要安装 JRE。GraalVM 支持提前(AOT)编译。
我一直认为虚拟机只是一台计算机本身,它可以在自己的隔离位置运行代码,但是对于 JVM,我认为这是不正确的,因为我认为 JVM 生成的机器代码仍然必须是在我们拥有的实际操作系统上运行。
是的。
术语“虚拟机”有多种含义:
如果您将 JVM 与其他类型的虚拟机混为一谈,您可能会陷入困境。别。它们的不同之处足以将概念混为一谈,而不会帮助您理解。