Java - 二进制代码与ByteCode相同吗?

24 java binary jvm bytecode

在Java中,"二进制代码"是否与"Java字节码"相同?

这是Java中的流程吗?

Java文件(.java) - > [javac] - > ByteCode文件(.class) - > [JVM/Java解释器] - >运行它(首先将其转换为特定于机器的二进制代码)

谢谢!

sgo*_*les 28

答案取决于你的意思binary code.

Java bytecode是一种二进制数据格式,包括Java虚拟机的加载信息和执行指令.从这个意义上说,Java bytecode是一种特殊的二进制代码.

当您使用术语" 二进制代码 "来表示真实处理器体系结构(如IA-32或Sparc)的机器指令时,它就不同了.从那个意义上讲,它
Java bytecode不是二进制代码.它不是特定于处理器的.


Max*_*xym 12

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)
Run Code Online (Sandbox Code Playgroud)

该流程中的每个步骤都很重要,可帮助JVM对代码进行一些优化.它当然不会改变你的算法,优化只是意味着可以检测到一些代码序列并用更好的代码交换(产生相同的结果).从LIR阶段开始,代码变为平台相关(!).

字节码可以很好地解释,但不足以轻易转换为机器本机代码.HIR负责处理它,其目的是将字节码快速转换为中间表示.MIR将所有操作转换为三操作数操作; ByteCode基于堆栈操作:

iload_0
iload_1
iand
Run Code Online (Sandbox Code Playgroud)

这是简单and操作的字节码,中间层表示将是以下几种:

and v0 v1 -> v2
Run Code Online (Sandbox Code Playgroud)

LIR依赖于平台,考虑到我们的简单and操作示例,并将我们的平台指定为x86,那么我们的代码片段将是:

x86_and v1 v0 -> v1
x86_move v1 -> v2
Run Code Online (Sandbox Code Playgroud)

因为and操作需要两个操作数,第一个是目标,另一个是源,然后我们将结果值放到另一个"变量".下一阶段是"寄存器分配",因为x86平台(可能大多数其他)使用寄存器,而不是变量(如中间表示),也不是堆栈(如字节码).这里我们的代码片段应如下所示:

x86_and eax ecx -> eax
Run Code Online (Sandbox Code Playgroud)

在这里你可以注意到没有"移动"操作.我们的代码只包含一行,JVM发现创建一个新的虚拟变量并不是必需的; 我们可以重用eax寄存器.如果代码足够大,有很多变量并且使用它们密集(例如在下面某处使用eax,所以我们无法更改其值),那么您将在机器代码中看到移动操作.这又是关于优化:)

这是JIT流程,但是根据VM的实现,还有一个步骤 - 如果代码被编译("热"),并且仍然执行了很多次,JVM会调度该代码的优化(例如使用内联).

好吧,结论是从字节码到机器代码的路径非常有趣,有点不可预见,并且取决于很多东西.

顺便说一下,上面描述的过程称为"混合模式解释"(当JVM首先解释字节码,然后使用JIT编译时),这种JVM的例子是HotSpot.一些JVM(如Oracle的JRockit)仅使用JIT编译.

这是对那里发生的事情的一个非常简单的描述.我希望它能够在很高的层次上理解JVM内部的流程,并且有助于解决字节码和二进制代码之间的差异问题.有关此处未提及且与该主题相关的参考和其他问题,请阅读类似主题" 为什么编译的Java类文件小于C编译文件? ".

也可以随意批评这个答案,指出我的错误或误解,我总是愿意提高我对JVM的认识:)


Dav*_*nco 7

没有"与机器无关的字节码"这样的东西(如果你考虑它就没有任何意义).字节码仅用于(就此答案而言)用于虚拟机之类的东西.虚拟机(如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)
Run Code Online (Sandbox Code Playgroud)

这是不正确的.JVM不会"转换"任何内容.它只是解释字节码.JVM中"转换"字节码的唯一部分是在调用JIT编译器时,这是一种特殊情况,不应该进行泛化.