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


Answers:


75

首先,我要说的是,我不认为Java字节码与MSIL之间的细微差别不会使.NET开发新手感到困扰。它们都具有定义抽象目标机器的相同目的,该目标机器是最终使用的物理机器之上的一层。

MSIL和Java字节码非常相似,实际上有一个名为Grasshopper的工具可以将MSIL转换为Java字节码,我是Grasshopper开发团队的一员,所以我可以分享一些(淡淡的)知识。请注意,.NET Framework 2.0发布后,我停止了这一工作,因此其中某些事情可能不再适用(如果这样,请发表评论,我会予以纠正)。

  • .NET允许用户定义的类型具有与常规引用语义(struct)相对应的值语义。
  • .NET支持无符号类型,这使指令集更加丰富。
  • Java在字节码中包括方法的异常规范。尽管异常规范通常仅由编译器强制执行,但是如果使用非默认的类加载器,则可以由JVM强制执行。
  • .NET泛型用IL表示,而Java泛型仅使用类型擦除
  • .NET属性在Java中没有等效项(是否仍然如此?)。
  • .NETenums不仅仅是整数类型的包装器,而Javaenums则是完全成熟的类(感谢Internet Friend)的评论)。
  • .NET具有outref参数。

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


关于属性-Java注释也可以设置为出现在字节码中,因此有一个等效项。
橡树

@Oak:Java批注仅允许传递数据,而.NET属性是功能强大的类,可能具有逻辑,最重要的是实现接口。
Fyodor Soikin 2011年

字节码还为每种返回类型提供了单独的返回指令,如果它实际上有助于类型安全,则不建议使用dunno。
塞西尔洗碗机

1
与.NET中的值类型具有值语义的事实相比,.NET中的值类型有时可能分配到琐碎的重要性; 每个值类型的存储位置一个实例。相比之下,Java中的每个存储位置都是原始的或混杂的对象引用。没有其他类型。
2013年

1
想知道他们如何比较性能吗?是MSIL更快地解释了例如字节码吗?
路加·奥布莱恩 Luke T O'Brien),

23

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汇编程序中,例如 ilasm.exe以创建可执行文件。如您所见,CIL是一种完全人类可读和可写的语言。您可以在任何文本编辑器中轻松创建有效的CIL程序。

您也可以使用编译javac器编译上述Java程序,然后通过javap“反汇编程序”运行生成的类文件以获取以下信息:

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
}

javap输出不编译(据我所知),但如果你把它比作CIL输出上面可以看到两个非常相似。


2
事实证明,已经尝试创建一种人类可读/可写的Java汇编语言。我发现的两个是JasminJava字节码汇编器
Justin

2
我在这里写的要好得多。与Jasmin不同,它的设计目的是能够反汇编和重新组装任何有效的类文件。github.com/Storyyeller/Krakatau。我认为微软提供标准的汇编器,而Java编码器必须自己编写,这会更准确。

22

他们本质上是在做同样的事情,MSIL是Microsoft的Java字节码版本。

内部的主要区别是:

  1. 字节码是为编译和解释开发的,而MSIL是为JIT编译明确开发的
  2. MSIL的开发是为了支持多种语言(C#和VB.NET等),而字节码仅是为Java编写的,导致字节码在语法上比Java更像Java,而IL在任何特定的.NET语言上都更类似于Java。
  3. MSIL在值和引用类型之间有更明确的划分

K John Gough这篇文章中可以找到更多的信息和详细的比较(后记文档)


“ 1.Bytecode是为编译和解释开发的,而MSIL是为JIT编译显式开发的”-这是关于Java代码如何编译为字节码以及如何解释字节码的内容。我对么?MSIL是否不会被解释为要执行?
阿卜杜勒

2

CIL(又称MSIL)旨在为人类可读。Java字节码不是。

可以将Java字节码看作是不存在的硬件(但可以模拟JVM)的机器代码。

CIL更像是汇编语言-距机器代码仅一步之遥,同时仍是人类可读的。


只要您具有十六进制编辑器,字节码实际上就非常容易阅读。这是一种非常简单的基于堆栈的语言,具有用于直接表示类和方法的扩展。我以为MSIL是较低级别的(例如寄存器)?
Daniel Spiewak

en.wikibooks.org/wiki/... en.wikibooks.org/wiki/... 一个是原始CIL。另一个是反汇编的字节码。如果您使用十六进制,则字节码可能是合理可读的,但这不是设计目的。
苗条的

“拆卸”确实是一个错误的词。可能是“解编码”。.class文件中的字节码仅出于紧凑性而无法读取。与javap的手册页相反,从编译的类生成可读的字节码不涉及反汇编。
Daniel Spiewak

2

差别不大。两者都是您编写的代码的中间格式。在执行时,虚拟机将执行托管的中间语言,这意味着虚拟机将控制变量和调用。甚至还有我现在不记得的一种语言,它可以以相同的方式在.Net和Java上运行。

基本上,这只是同一件事的另一种格式

编辑:找到了语言(除了Scala):是FAN(http://www.fandev.org/),看起来很有趣,但是还没有时间评估


可以将Scala编译为以JVM或CLR为目标,分别生成字节码或MSIL。
Daniel Spiewak

很高兴知道,但是一个月前我在阅读DZone时发现了另一种语言:找到了!请参阅我的帖子的编辑
GHad

1

同意,差异足够细微,可以初学者学习。如果您想从基础开始学习.Net,建议您查看一下公共语言基础结构和公共类型系统。



1

我认为MSIL不应与Java字节码进行比较,而应与“组成Java字节码的指令”进行比较。

没有反汇编的Java字节码的名称。“ Java字节码”应该是非官方的别名,因为我在官方文档中找不到它的名称。 Java类文件反汇编器

为类中的每个方法打印出反汇编的代码,即组成Java字节码的指令。这些都记录在Java虚拟机规范中。

“ Java VM指令”和“ MSIL”都被组装为.NET字节码和Java代码,它们是人类不可读的。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.