【问题标题】:Differences between MSIL and Java bytecode?MSIL 和 Java 字节码的区别?
【发布时间】:2010-09-10 20:15:39
【问题描述】:

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

【问题讨论】:

标签: java .net bytecode cil


【解决方案1】:

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

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

  • .NET 允许用户定义的类型具有与 regular 引用语义相对应的值语义 (struct)。
  • .NET 支持无符号类型,这使得指令集更加丰富。
  • Java 在字节码中包含方法的异常规范。虽然异常规范通常只由编译器强制执行,但如果使用了默认类加载器以外的类加载器,它可能会由 JVM 强制执行。
  • .NET 泛型用 IL 表示,而 Java 泛型仅使用 type erasure
  • .NET 属性在 Java 中没有等价物(这仍然是真的吗?)。
  • .NET enums 只不过是整数类型的包装器,而 Java enums 是非常成熟的类(感谢 Internet Friend 的评论)。
  • .NET 有outref 参数。

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

【讨论】:

  • 关于属性 - Java 注释也可以设置为出现在字节码中,所以有一个等价物。
  • @Oak:Java 注解只允许传递数据,而 .NET 属性是完全支持的类,它可能有逻辑,最重要的是,实现接口。
  • 字节码对每种返回类型都有单独的返回指令,不知道它是否真的有助于类型安全。
  • 与具有值语义的事实相比,.NET 中的值类型有时可能在堆栈上分配这一事实是微不足道的;每个值类型的存储位置都是一个实例。相比之下,Java 中的每个存储位置要么是原始的,要么是混杂的对象引用;没有其他类型。
  • 想知道他们如何比较性能吗? MSIL 比例如字节码的解释速度更快吗?
【解决方案2】:

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

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

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

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

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

我应该注意到 JVM(它们中的大多数)比 CLR(它们中的任何一个)的优化程度更高。因此,原始性能可能是更喜欢以 Java 字节码为目标的原因。这是一个实现细节。

有人说 Java 字节码被设计为多平台,而 CIL 被设计为仅适用于 Windows。不是这种情况。 .NET 框架中有一些“Windows”主义,但 CIL 中没有。

作为上面第 4) 点的示例,我不久前为 CIL 编译器编写了一个玩具 Java。如果你给这个编译器提供以下 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 程序,可以将它输入到像 ilasm.exe 这样的 CIL 汇编程序中以创建可执行文件。如您所见,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 输出进行比较,您会发现两者非常相似。

【讨论】:

  • 事实证明,已经有人尝试创建一种人类可读/可写的 Java 汇编语言。我发现的两个是JasminJava Bytecode Assembler
  • 我在这里写了一个更好的。与 Jasmin 不同,它被设计为能够反汇编和重新组装任何有效的类文件。 github.com/Storyyeller/Krakatau。我认为更准确的说法是,Microsoft 提供标准的汇编程序,而 Java 编码人员必须自己制作。
【解决方案3】:

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

内部的主要区别是:

  1. 字节码是为编译和解释而开发的,而 MSIL 是专门为 JIT 编译而开发的
  2. MSIL 旨在支持多种语言(C# 和 VB.NET 等),而 Bytecode 仅针对 Java 编写,导致 Bytecode 在语法上更类似于 Java,而不是 IL 与任何特定 .NET 语言的相似度
  3. MSIL 在值和引用类型之间有更明确的描述

更多信息和详细比较可以在this article by K John Gough(后记文档)中找到

【讨论】:

  • "1.Bytecode 是为编译和解释而开发的,而 MSIL 是为 JIT 编译而显式开发的" - 这是关于如何将 Java 代码编译为字节码以及如何解释字节码。我对么? MSIL 不会被解释为执行吗?
【解决方案4】:

CIL 又名 MSIL 旨在供人类阅读。 Java 字节码不是。

将 Java 字节码视为不存在(但 JVM 模拟)的硬件的机器代码。

CIL 更像是汇编语言 - 与机器代码相距一步,但仍然是人类可读的。

【讨论】:

  • 字节码实际上是非常可读的,只要你有一个十六进制编辑器。它是一种非常简单的基于堆栈的语言,具有用于直接表示类和方法的扩展。我认为 MSIL 是较低级别的(例如寄存器)?
  • en.wikibooks.org/wiki/… en.wikibooks.org/wiki/… 一个是原始 CIL。另一种是反汇编字节码。如果你 grok hex,字节码可能是相当可读的,但这不是设计目标。
  • “拆解”确实是一个错误的词。 “解码”也许。字节码在 .class 文件中是不可读的,仅仅是为了紧凑。与 javap 的手册页不同,从已编译的类生成可读字节码不涉及反汇编。
【解决方案5】:

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

基本上,它只是同一事物的另一种格式

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

【讨论】:

  • Scala 可以编译为针对 JVM 或 CLR,分别生成字节码或 MSIL。
  • 很高兴知道,但一个月前我在阅读 DZone 时发现了另一种语言:找到了!查看我的帖子的编辑
【解决方案6】:

同意,差异很小,初学者可以理解。如果您想从基础开始学习 .Net,我建议您查看 Common Language Infrastructure 和 Common Type System。

【讨论】:

    【解决方案7】:

    Serge Lidin 撰写了一本关于 MSIL 细节的不错的书:Expert .NET 2.0 IL Assembler。通过查看使用.NET ReflectorIldasm (Tutorial) 的简单方法,我还能够快速掌握MSIL。

    MSIL 和 Java 字节码的概念非常相似。

    【讨论】:

      【解决方案8】:

      我认为 MSIL 不应该与 Java 字节码相比,而是“构成 Java 字节码的指令”。

      没有反汇编java字节码的名字。 “Java Bytecode”应该是一个非官方的别名,因为我在官方文档中找不到它的名字。 The Java Class File Disassembler

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

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-12-06
        • 2010-09-06
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多