作为对名为Differences between MSIL and Java bytecode?的问题的跟进,Java虚拟机的工作方式与.NET Framework公共(public)语言运行时(CLR)的工作方式(主要)区别或相似之处是什么?

另外,.NET Framework CLR是“虚拟机”还是不具有虚拟机的属性?

最佳答案

两种实现之间有很多相似之处(我认为:是的,它们都是“虚拟机”)。

一方面,它们都是基于堆栈的VM,没有“寄存器”的概念,就像我们过去经常在x86或PowerPC这样的现代CPU中看到的那样。通过将操作数插入“堆栈”,然后每当一条指令(加法,除法等)需要使用这些操作数时,将这些操作数从堆栈中弹出,即可对所有表达式((1 + 1)/2)求值。每条指令将其结果压回堆栈。

这是一种实现虚拟机的便捷方法,因为世界上几乎每个CPU都有一个堆栈,但是寄存器的数量通常是不同的(某些寄存器是专用的,每个指令期望其操作数位于不同的寄存器中,依此类推。 )。

因此,如果您要对抽象机进行建模,那么纯粹基于堆栈的模型是一种不错的选择。

当然,真正的机器不会以这种方式运行。因此,JIT编译器负责执行字节码操作的“注册”,实质上是尽可能地调度实际的CPU寄存器以包含操作数和结果。

因此,我认为这是CLR和JVM之间最大的共性之一。

至于差异...

两种实现之间的一个有趣的区别是,CLR包含用于创建泛型类型,然后将参数特化应用于这些类型的指令。因此,在运行时,CLR认为List 与List 是完全不同的类型。

在幕后,它为所有引用类型特化使用相同的MSIL(因此List 使用与List 相同的实现,在API边界具有不同的类型转换),但是每种值类型使用它自己的独特实现(List 生成与List 完全不同的代码)。

在Java中,泛型是纯粹的编译技巧。 JVM不知道哪些类具有类型参数,并且无法在运行时执行参数专用化。

从实际的角度来看,这意味着您不能在泛型类型上重载Java方法。您不能有两个具有相同名称的不同方法,仅在它们接受List 或List 上有所不同。当然,由于CLR知道参数类型,因此它没有在通用类型专门化方面重载的问题处理方法。

在日常工作中,这就是我最注意到的CLR与
JVM。

其他重要区别包括:

  • CLR具有闭包(作为C#委托(delegate)实现)。 JVM仅从Java 8开始才支持闭包。
  • CLR具有协程(通过C#'yield'关键字实现)。 JVM没有。
  • CLR允许用户代码定义新的值类型(结构),而JVM提供固定的值类型集合(字节,短型,整型,长型,浮点型, double 型,字符型, boolean 型),并且仅允许用户定义新的引用类型(类)。
  • CLR为声明和操作指针提供支持。这特别有趣,因为JVM和CLR均采用严格的世代压缩垃圾收集器实现作为其内存管理策略。在通常情况下,严格的压缩GC很难使用指针,因为将值从一个存储位置移动到另一个存储位置时,所有指针(和指向指针的指针)都将变为无效。但是CLR提供了一种“固定”机制,以便开发人员可以声明一个代码块,不允许CLR在其中移动某些指针。非常方便
  • JVM中最大的代码单元是“保护”关键字所证明的“包”,或者是能够在类路径中指定jar并将其像对待一样的JAR(即Java ARchive)。代码文件夹。在CLR中,类被聚合为“程序集”,而CLR提供推理和操纵程序集的逻辑(程序集被加载到“AppDomains”中,提供子应用程序级沙箱用于内存分配和代码执行)。
  • CLR字节码格式(由MSIL指令和元数据组成)具有的指令类型少于JVM。在JVM中,每个唯一操作(添加两个int值,添加两个float值等)都有自己的唯一指令。在CLR中,所有MSIL指令都是多态的(加两个值),而JIT编译器负责确定操作数的类型并创建适当的机器代码。不过,我不知道哪个是最好的策略。两者都有权衡。适用于JVM的HotSpot JIT编译器可以使用更简单的代码生成机制(由于操作数已经在指令中进行编码,因此无需确定操作数类型),但这意味着它需要更复杂的字节码格式,具有更多指令类型。

  • 我一直在使用Java(并欣赏JVM)已有十年了。

    但是,我认为,几乎在所有方面,CLR都是卓越的实现。

    10-01 19:27
    查看更多