在Java中,“二进制代码”是否与“Java字节码”相同?
这是Java中的流程吗?
Java文件(.java) - > [javac] - > ByteCode文件(.class) - > [JVM / Java的 翻译] - >运行它(首先 将其转换为二进制代码 特定于机器)
谢谢!
答案 0 :(得分:27)
答案取决于 binary code
的含义。
Java bytecode
是一种二进制数据格式,包含Java虚拟机的加载信息和执行指令。从这个意义上说, Java bytecode
是一种特殊的二进制代码。
当您使用术语“二进制代码”来表示真实处理器体系结构(如IA-32或Sparc)的机器指令时,它会有所不同。
在这个意义上, Java bytecode
不是二进制代码。它不是特定于处理器的。
答案 1 :(得分:12)
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
在这里你可以注意到没有“移动”操作。我们的代码只包含一行,JVM发现创建一个新的虚拟变量并不是必需的;我们可以重用eax
寄存器。如果代码足够大,有很多变量并且使用它们密集(例如在下面的某处使用eax,所以我们无法更改它的值),那么您将在机器代码中看到移动操作。这又是关于优化的:)
那是JIT流程,但是根据VM的实现,还有一个步骤 - 如果代码被编译(“热”),并且仍然执行了很多次,JVM会调度该代码的优化(例如使用内联)。
嗯,结论是从字节码到机器码的路径非常有趣,有点不可预见,并且取决于很多东西。
顺便说一句,上面描述的过程称为“混合模式解释”(当JVM首先解释字节码,然后使用JIT编译时),这种JVM的例子是HotSpot。一些JVM(如Oracle的JRockit)仅使用JIT编译。这是对那里发生的事情的一个非常简单的描述。我希望它能够在很高的层次上理解JVM内部的流程,并且有助于解决字节码和二进制代码之间的差异问题。有关此处未提及且与该主题相关的参考和其他问题,请阅读类似主题“Why are compiled Java class files smaller than C compiled files?”。
也可以随意批评这个答案,指出我的错误或误解,我总是愿意提高我对JVM的认识:)
答案 2 :(得分:7)
没有“与机器无关的字节码”这样的东西(如果你考虑它就没有任何意义)。字节码仅用于(就此答案而言)用于虚拟机之类的东西。 VM(如JVM) INTERPRET 字节码并使用一些巧妙而复杂的即时编译( IS 依赖于机器/平台)为您提供最终结果产品
所以从某种意义上说,这两个答案都是对的。 Java编译器将代码编译为Java字节码(与机器无关)。字节码所在的*.class
文件是二进制的 - 毕竟它们是可执行的。虚拟机稍后会解释这些二进制*.class
文件(注意:当将文件描述为二进制文件时,它有点用词不当)并且会执行各种令人敬畏的事情。通常,JVM使用称为JIT(即时编译)的东西,它生成特定于平台或特定于机器的指令,以加速执行的各个部分。然而,JIT是另一天的另一个话题。
修改强>:
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编译器时,这是一种特殊情况,不应该进行泛化。
答案 3 :(得分:4)
C / C ++(以身份为例)和Java程序都编译成 二进制代码 。此通用术语仅表示新创建的文件不以人类可读的方式对指令进行编码。 (即您将无法在文本程序中打开已编译的文件并阅读它。)
另一方面,二进制0和1的编码(或表示)取决于编译器生成的内容。对于Java,它会生成名为 字节码 的指令,这些指令由JVM解释。在其他情况下,对于其他语言,它可能会生成IA-32或SPARC指令。
总之,术语 二进制代码 和 Java字节码 相互对立的方式具有误导性。原因是区分了机器相关的普通二进制代码和不是的Java字节代码(也是二进制代码)。
答案 4 :(得分:1)
我今天发现上述问题的答案:
来源:JLS
加载是指查找具有特定名称的类或接口类型的二进制形式的过程,可能是通过动态计算,但更常见的是通过检索先前由Java编译器从源代码计算的二进制表示,并从该二进制形式构造一个Class对象来表示类或接口。
加载的精确语义在Java Java Machine Specification,Java SE 7 Edition的第5章中给出。在这里,我们从Java编程语言的角度概述了该过程。
类或接口的二进制格式通常是上面引用的Java虚拟机规范Java SE 7中描述的类文件格式,但只要符合要求,其他格式也是可能的§13.1中规定。类ClassLoader的方法defineClass可用于从类文件格式的二进制表示中构造Class对象。
答案 5 :(得分:0)
谈论程序时,术语“ 二进制代码”通常表示二进制形式的可执行程序(编码为位序列)。 换句话说,二进制代码是任何编译程序,而不是脚本,它们以文本形式分发和执行(解释)。>
二进制代码可以有两种:机器码和字节码。 机器代码是根据实际硬件微处理器的规范编码的程序。因此,它可以直接由目标微处理器执行,而无需任何其他软件的中介。相反,字节码是根据某些虚拟微处理器(虚拟机)的规范编码的程序。因此,对于执行而言,可以将其解释为或翻译成机器代码,然后直接执行。
通过这种方式,每个字节码都是一个二进制码,但是并不是每个 binary code 都是 bytecode 。就您的问题而言,“ Java字节码”无条件是“二进制码”,但是“二进制码”不一定是“ Java字节码”,而可以是“ Java字节码”。