MSIL 和 Java 字节码之间的区别?

2022-08-31 12:16:39

我是 .Net 的新手,我正试图首先了解基础知识。MSIL 和 Java 字节码有什么区别?


答案 1

首先让我说,我不认为Java字节码和MSIL之间的细微差异应该困扰新手.NET开发人员。它们都具有相同的目的,即定义一个抽象的目标机器,该目标机器是最终使用的物理机器之上的一层。

MSIL和Java字节码非常相似,实际上有一个名为Grasshopper的工具,它将MSIL转换为Java字节码,我是Grasshopper开发团队的一员,所以我可以分享一些我(褪色的)知识。请注意,当.NET framework 2.0问世时,我停止了这方面的工作,所以其中一些事情可能不再正确(如果是这样,请发表评论,我会纠正它)。

  • .NET 允许用户定义的类型将具有值语义应用于常规引用语义 ()。struct
  • .NET 支持无符号类型,这使得指令集更加丰富。
  • Java 在字节码中包含方法的异常规范。尽管异常规范通常仅由编译器强制执行,但如果使用缺省类装入器以外的类装入器,则 JVM 可能会强制执行异常规范。
  • .NET 泛型以 IL 表示,而 Java 泛型仅使用类型擦除
  • .NET属性在Java中没有等效属性(现在仍然如此吗?)。
  • .NET只不过是整数类型的包装器,而Java枚举几乎是完全成熟的类(感谢Internet Friend的评论)。enums
  • .NET 具有 和 参数。outref

还有其他语言差异,但其中大多数不是在字节码级别表达的,例如,如果内存服务于Java的非内部类(在.NET中不存在)不是字节码功能,编译器会生成一个额外的参数到内部类的构造函数并传递外部对象。.NET lambda 表达式也是如此。static


答案 2

CIL(MSIL 的专有名称)和 Java 字节码的相同程度大于不同程度。但是,有一些重要的区别:

1)CIL从一开始就被设计为多种语言的目标。因此,它支持更丰富的类型系统,包括有符号和无符号类型、值类型、指针、属性、委托、事件、泛型、具有单个根的对象系统等。CIL 支持初始 CLR 语言(C# 和 VB.NET)不需要的功能,如全局函数和尾部调用优化。相比之下,Java字节码被设计为Java语言的目标,并反映了Java本身的许多约束。使用Java字节码编写C或Scheme会困难得多。

2) CIL 旨在轻松集成到本机库和非托管代码中

3)Java字节码被设计为解释或编译,而CIL的设计假设只有JIT编译。也就是说,Mono的初始实现使用解释器而不是JIT。

4)CIL被设计(并指定)为具有人类可读和可写的汇编语言形式,该形式直接映射到字节码形式。我相信Java字节码(顾名思义)意味着只有机器可读。当然,Java字节码相对容易反编译回原来的Java,如下图所示,它也可以“反汇编”。

我应该注意的是,JVM(大多数)比CLR(其中任何一个)都高度优化。因此,原始性能可能是首选面向 Java 字节码的原因。不过,这是一个实现细节。

有人说Java字节码被设计为多平台,而CIL被设计为仅Windows。事实并非如此。.NET框架中有一些“Windows”主义,但CIL中没有。

作为上面第4点的一个例子,我不久前写了一个玩具Java到CIL编译器。如果向此编译器提供以下 Java 程序:

class Factorial{
    public static void main(String[] a){
    System.out.println(new Fac().ComputeFac(10));
    }
}

class Fac {
    public int ComputeFac(int num){
    int num_aux ;
    if (num < 1)
        num_aux = 1 ;
    else 
        num_aux = num * (this.ComputeFac(num-1)) ;
    return num_aux ;
    }
}

我的编译器将吐出以下 CIL:

.assembly extern mscorlib { }
.assembly 'Factorial' { .ver  0:0:0:0 }
.class private auto ansi beforefieldinit Factorial extends [mscorlib]System.Object
{
   .method public static default void main (string[] a) cil managed
   {
      .entrypoint
      .maxstack 16
      newobj instance void class Fac::'.ctor'()
      ldc.i4 3
      callvirt instance int32 class Fac::ComputeFac (int32)
      call void class [mscorlib]System.Console::WriteLine(int32)
      ret
   }
}

.class private Fac extends [mscorlib]System.Object
{
   .method public instance default void '.ctor' () cil managed
   {
      ldarg.0
      call instance void object::'.ctor'()
      ret
   }

   .method public int32 ComputeFac(int32 num) cil managed
   {
      .locals init ( int32 num_aux )
      ldarg num
      ldc.i4 1
      clt
      brfalse L1
      ldc.i4 1
      stloc num_aux
      br L2
   L1:
      ldarg num
      ldarg.0
      ldarg num
      ldc.i4 1
      sub
      callvirt instance int32 class Fac::ComputeFac (int32)
      mul
      stloc num_aux
   L2:
      ldloc num_aux
      ret
   }
}

这是一个有效的 CIL 程序,可以馈送到 CIL 汇编程序中,就像创建可执行文件一样。如您所见,CIL是一种完全人类可读和可写的语言。您可以在任何文本编辑器中轻松创建有效的 CIL 程序。ilasm.exe

您还可以使用编译器编译上面的Java程序,然后通过“反汇编器”运行生成的类文件,以获得以下内容:javacjavap

class Factorial extends java.lang.Object{
Factorial();
  Code:
   0:   aload_0
   1:   invokespecial   #1; //Method java/lang/Object."<init>":()V
   4:   return

public static void main(java.lang.String[]);
  Code:
   0:   getstatic   #2; //Field java/lang/System.out:Ljava/io/PrintStream;
   3:   new #3; //class Fac
   6:   dup
   7:   invokespecial   #4; //Method Fac."<init>":()V
   10:  bipush  10
   12:  invokevirtual   #5; //Method Fac.ComputeFac:(I)I
   15:  invokevirtual   #6; //Method java/io/PrintStream.println:(I)V
   18:  return

}

class Fac extends java.lang.Object{
Fac();
  Code:
   0:   aload_0
   1:   invokespecial   #1; //Method java/lang/Object."<init>":()V
   4:   return

public int ComputeFac(int);
  Code:
   0:   iload_1
   1:   iconst_1
   2:   if_icmpge   10
   5:   iconst_1
   6:   istore_2
   7:   goto    20
   10:  iload_1
   11:  aload_0
   12:  iload_1
   13:  iconst_1
   14:  isub
   15:  invokevirtual   #2; //Method ComputeFac:(I)I
   18:  imul
   19:  istore_2
   20:  iload_2
   21:  ireturn
}

输出是不可编译的(据我所知),但是如果您将其与上面的CIL输出进行比较,您可以看到两者非常相似。javap


推荐