Java运行时环境和.NET框架在编译过程方面有何区别?

14

我正在学习通过 .NETJRE 框架将源代码转换为机器码。首先,我进行了一些研究,比较了这两个过程,并创建了这个图表。我需要帮助批评其正确性,更重要的是添加任何我遗漏的严肃内容以更好地理解编译路径。

输入图像描述


3
“assembler”在这里是什么意思?从现在看,不对:CLR/JVM并不生成汇编代码,而是直接生成机器码。至少JVM(我不认为CLR会)可以生成汇编作为副产品,但那几乎是没必要的。 - Voo
@Voo,我指的是一种程序,它可以将人类可读的汇编代码转换为CPU架构可以理解的机器码。我确实认为这可能在过程中完全是多余的。 - jII
1
@EJP,Voo 表示 JVM 会创建机器码,而不是生成字节码的 Java 编译器。 - jII
1
大多数现代编译器不会生成人类可读的汇编代码,然后再将其汇编成机器码,而是直接创建机器码。 - Thorbjørn Ravn Andersen
@jesterli 没错,那个可以被移除。如果需要的话(仅限JVM),汇编代码可以在额外的步骤中生成,但通常我们直接生成本地代码。 - Voo
使用术语“平台”来描述CLR/JVM是CIL/字节码运行的基础,这种用法是否正确?那么,“框架”这个术语应该如何使用呢? - jII
1个回答

16

.NET和Java都会编译成字节码,这是一种中间语言,其中包含虚拟机的指令。它不是机器码,因为无法直接在物理机器上运行。相反,现在运行时会启动即时编译器将VM指令转换为本地代码,然后直接运行。这比仅解释有很大的性能优势。

在这方面,它们略有不同。Oracle的Java实现(Hotspot)使用巧妙的解释、测量和JIT编译,只编译那些经常使用的部分,其余部分则进行解释。这是为了减少JIT编译器的初始影响(否则需要提前运行,从而延长进程启动时间),同时仍然允许在需要的地方获得良好的性能。另一方面,.NET总是JIT编译所有被使用的代码(未使用的代码不会被编译)。

编辑(2019):到目前为止,.NET也有分层编译,根据运行的代码来进一步优化代码。

至于您在评论中提到的问题:是的,CLR和JVM就是这些程序运行的平台。虚拟机也是一种机器,但不太像硬件。它们都与相应的框架紧密集成,.NET为基础类库,Java为Java类库。这些都是框架。


请问您能否解释一下“在.NET中,程序集是编译单元”的意思? - jII
3
在Visual Studio中,一个项目所看到的内容会被编译成一个单独的 .exe.dll 文件,也就是编译后的程序集。编译单元指的是最小的可编译单元,如果要进行部分重新编译就会变得很重要。例如,在Java中,您只需要重新编译已更改的类,在.NET中,您需要重新编译整个项目。请注意,对于大多数情况来说,这种差异微不足道--两个平台的编译器都非常快,特别是与C++相比。 - Joey
对于Java的.class重新编译,我给予+1。我之前没有意识到这一点,但在查看obj文件夹后,显然.NET不会为每个类分离对象结果。可以将类分离到库中以减少重新编译,但Java明确地将每个类分开。 - Martheen
1
@Joey,你似乎把编译代码和JIT编译混淆了。我不知道JVM Jitter是如何工作的,但这并不意味着CLR必须一次性JIT编译整个程序集。 JIT的含义就是“即时编译”,CLR也不例外。它会将要执行的代码即时编译为机器码,而这几乎总是单个方法(实际上,在高度简化的视图中,CLR维护一个方法表,该表指向Jitter,当Jitter将方法编译为机器码时,它会更新方法表以指向刚刚编译好的机器码方法)。 - Amit Mittal
1
@Martheen 如果Java类被打包成JAR文件,如果您更新了一个类,那么您需要重新生成JAR文件。同样地,如果您更改了.NET中的任何类,则必须重新生成程序集。只是.NET没有提供不使用打包部署/使用类的选项。此外,Visual Studio提供了一个构建/重建选项。构建(智能)仅编译源代码中已更改的内容(它比类的编译单元更细粒度),然后更新和重新打包程序集,而重建则重新编译整个程序集。 - Amit Mittal
显示剩余8条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接