这是Java的流程吗?
谢谢!Java文件(.java) -> [javac] -> 字节码文件(.class)- > [JVM/Java解释器] -> 运行它(首先将其转换为特定于机器的二进制代码)
谢谢!Java文件(.java) -> [javac] -> 字节码文件(.class)- > [JVM/Java解释器] -> 运行它(首先将其转换为特定于机器的二进制代码)
二进制代码
的理解。
Java字节码
是一种二进制数据格式,包括Java虚拟机的加载信息和执行指令。在这个意义上,Java字节码
是一种特殊类型的二进制代码。Java字节码
在这个意义上不是一个二进制代码。它不是特定于处理器的。JVM是一个非常复杂的程序,其中的流程在某种程度上是不可预测的。例如,在HotSpot JVM内部的流程大致如下:
1)它获取您的字节码并解释执行
2)如果某个方法被频繁执行(在某个时间段内执行了一定次数),则将其标记为“热”方法,并且JVM安排将其编译成平台相关的机器代码(这就是您所说的二进制代码吗?)。该流程如下所示:
ByteCode
--> Hige-level Intermediate Representation (HIR)
--> Middle-level Intermediate Representation (MIR)
--> Low-level Intermediate Representation (LIR)
--> Register Allocation
--> EMIT (platform dependent machine code)
这个流程中的每一步都很重要,有助于JVM对您的代码进行一些优化。当然,这不会改变您的算法,优化只是意味着可以检测到某些代码序列并用性能更好的代码进行替换(产生相同的结果)。从LIR阶段开始,代码变得依赖于平台(!)。
字节码可能适合解释,但不足以轻松转换成机器本地代码。HIR负责此事,其目的是将字节码快速转换为中间表示。MIR将所有操作转换为三操作数操作;ByteCode基于堆栈操作:
iload_0
iload_1
iand
这是简单的and
操作的字节码,对应的中间表示形式如下:
and v0 v1 -> v2
LIR依赖于平台,在考虑我们使用and
操作的简单示例并将我们的平台指定为x86时,我们的代码片段将如下所示:
x86_and v1 v0 -> v1
x86_move v1 -> v2
因为and
操作需要两个操作数,第一个是目标,另一个是源,然后我们将结果值放入另一个"变量"中。下一阶段是"寄存器分配",因为x86平台(以及可能大多数其他平台)使用寄存器而不是变量(如中间表示)或堆栈(如字节码)。在这里,我们的代码片段应该像以下内容:
x86_and eax ecx -> eax
Java File (.java) -> [javac.exe] -> ByteCode File (.class) -> [JVM/Java Interpreter] -> Running it(by first converting it into binary code specific to the machine)
这是不正确的。JVM并没有“转换”任何东西。它只是解释字节码。JVM中唯一“转换”字节码的部分是当调用JIT编译器时,这是一个特殊情况,不应该概括。
以 C/C++ 和 Java 为例,这两种编程语言的程序都会被编译成二进制代码。这个通用术语的意思是新创建的文件不会以人类可读的方式编码指令(也就是说,你无法在文本程序中打开已编译的文件并阅读它)。
另一方面,二进制的 0 和 1 所代表的内容(或表示的含义)取决于编译器生成的内容。在 Java 的情况下,它会生成称为字节码的指令,由 JVM 解释执行。而对于其他语言,则可能生成 IA-32 或 SPARC 指令。
总之,将二进制代码和Java 字节码这两个术语相对立是具有误导性的。其原因是要区分机器相关的普通二进制代码和非机器相关的 Java 字节码(同样是二进制代码)。
我今天找到的答案如下:
来源:JLS
加载是指查找具有特定名称的类或接口类型的二进制形式的过程,可以通过实时计算进行,也可以更常见地通过从Java编译器先前从源代码中检索计算出来的二进制表示,并从该二进制形式构造一个Class对象来表示类或接口。
加载的精确语义在Java虚拟机规范第5章中给出,Java SE 7版。这里我们从Java编程语言的角度概述这个过程。
类或接口的二进制格式通常是《Java虚拟机规范》,Java SE 7版中描述的类文件格式,但其他格式也可能是可行的,只要它们符合§13.1中指定的要求。ClassLoader类的defineClass方法可以用于从类文件格式中的二进制表示构造Class对象。