MSILとJavaバイトコードの違いは?


回答:


75

まず最初に、JavaバイトコードとMSILの微妙な違いは、初心者の.NET開発者を悩ませるべきものではないと思います。これらは両方とも、最終的に使用される物理マシンの上のレイヤーである抽象的なターゲットマシンを定義するという同じ目的を果たします。

MSILとJavaバイトコードは非常に似ています。実際、MSILをJavaバイトコードに変換するGrasshopperというツールがあります。私はGrasshopperの開発チームの一員だったので、(色あせた)知識を少し共有できます。.NET Framework 2.0がリリースされたときにこれに取り組むのをやめたので、これらのいくつかはもう真実ではないかもしれないことに注意してください(もしそうなら、コメントを残してください、そして私はそれを修正します)。

  • .NETでは、通常の参照セマンティクス(struct)に加えて、値セマンティクスを持つユーザー定義型を使用できます。
  • .NETは符号なし型をサポートしているため、命令セットが少し豊富になります。
  • Javaでは、バイトコードにメソッドの例外仕様が含まれています。例外仕様は通常、コンパイラによってのみ適用されますが、デフォルト以外のクラスローダーが使用されている場合は、JVMによって適用される場合があります。
  • .NETジェネリックはILで表現されますが、Javaジェネリックは型消去のみを使用します。
  • .NET属性はJavaに相当するものがありません(これはまだ本当ですか?)。
  • .NETenumsは整数型のラッパーにすぎませんが、Javaenumsはほぼ本格的なクラスです(コメントしてくれたInternet Friendに感謝します)。
  • .NETにはパラメータがoutありrefます。

他の言語の違いはありますが、それらのほとんどはバイトコードレベルで表現されていません。たとえば、メモリがJavaの非static内部クラス(.NETには存在しない)を提供する場合、バイトコード機能ではない場合、コンパイラは次の追加の引数を生成します。内部クラスのコンストラクターであり、外部オブジェクトを渡します。同じことが.NETラムダ式にも当てはまります。


属性について-Javaアノテーションはバイトコードにも表示されるように設定できるため、同等のものがあります。
オーク

@Oak:Javaアノテーションはデータの受け渡しのみを許可しますが、.NET属性は完全に機能するクラスであり、ロジックを持ち、最も重要なこととして、インターフェースを実装します。
Fyodor Soikin 2011

バイトコードには、戻り値の型ごとに個別の戻り値の型もありますが、実際に型の安全性に役立つかどうかはわかりません。
セシル食器洗い機2013年

1
.NETの値型がスタックに割り当てられることがあるという事実は、それらが値セマンティクスを持っているという事実と比較して、ささいな重要性を持っています。すべての値型の保存場所インスタンスです。対照的に、Javaのすべての格納場所は、プリミティブまたは無差別のオブジェクト参照です。他のタイプはありません。
スーパーキャット2013

1
彼らがパフォーマンスをどのように比較するのか疑問に思っていましたか?MSILは、たとえばバイトコードよりも解釈が速いですか?
ルークTオブライエン

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 Frameworkにはいくつかの「Windows」主義がありますが、CILにはありません。

上記のポイント番号4)の例として、しばらく前におもちゃのJava toCILコンパイラを作成しました。このコンパイラに次の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
   }
}

これはilasm.exe、実行可能ファイルを作成するようにCILアセンブラにフィードできる有効なCILプログラムです。ご覧のとおり、CILは完全に人間が読める形式と書き込み可能な言語です。有効なCILプログラムは、任意のテキストエディタで簡単に作成できます。

上記のJavaプログラムをjavacコンパイラでコンパイルしてから、結果のクラスファイルを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は非常に似ていることがわかります。


2
人間が読み取り/書き込み可能なJavaアセンブリ言語を作成する試みが行われていることが判明しました。私が見つけた2つは、JasminJava Bytecode Assembler
Justin

2
私はここにもっと良いものを書きました。Jasminとは異なり、有効なクラスファイルを逆アセンブルおよび再アセンブルできるように設計されています。github.com/Storyyeller/Krakatau。Microsoftは標準のアセンブラーを提供しているのに対し、Javaコーダーは独自に作成する必要があると言った方が正確だと思います。
アンチモン2013年

22

彼らは本質的に同じことをしています。MSILはMicrosoftのバージョンのJavaバイトコードです。

内部の主な違いは次のとおりです。

  1. バイトコードはコンパイルと解釈の両方のために開発されましたが、MSILはJITコンパイルのために明示的に開発されました
  2. MSILは、複数の言語(C#やVB.NETなど)をサポートするために開発されましたが、バイトコードはJava専用に記述されているため、バイトコードは、ILが特定の.NET言語よりも構文的にJavaに似ています。
  3. MSILには、値型と参照型の間のより明確な描写があります

K John Goughによるこの記事(追記文書)には、さらに多くの情報と詳細な比較が記載されています。


「1.Bytecodeはコンパイルと解釈の両方のために開発されましたが、MSILはJITコンパイルのために明示的に開発されました」-これは、Javaコードがバイトコードにコンパイルされる方法とそのバイトコードが解釈される方法について説明しています。私は正しいですか?MSILは実行されると解釈されませんか?
アブドゥル

2

CIL(別名MSIL)は、人間が読める形式にすることを目的としています。Javaバイトコードはそうではありません。

Javaバイトコードは、存在しない(ただし、JVMがエミュレートする)ハードウェアのマシンコードであると考えてください。

CILは、アセンブリ言語に似ています。人間が読める形式でありながら、機械語から1ステップです。


16進エディタを使用している限り、バイトコードは実際には非常に読みやすくなっています。これは、クラスとメソッドを直接表現するための拡張機能を備えた、非常に単純なスタックベースの言語です。MSILは低レベル(レジスタなど)だと思いましたか?
Daniel Spiewak 2008

en.wikibooks.org/wiki/... en.wikibooks.org/wiki/... 一つは、生CIL。もう1つは、逆アセンブルされたバイトコードです。16進数を使用する場合、バイトコードはかなり読みやすいかもしれませんが、それは設計の目的ではありません。
スリム

「逆アセンブル」は本当に間違った言葉です。多分「エンコード解除」。単にコンパクトにするために、.classファイルでバイトコードを読み取ることはできません。javapのマニュアルページとは異なり、コンパイルされたクラスから読み取り可能なバイトコードを生成するための逆アセンブルはありません。
Daniel Spiewak 2008

2

それほど大きな違いはありません。どちらも、作成したコードの中間形式です。実行されると、仮想マシンは管理対象の中間言語を実行します。つまり、仮想マシンが変数と呼び出しを制御します。.NetとJavaで同じように実行できる、今は覚えていない言語もあります。

基本的に、それは同じことのための単なる別のフォーマットです

編集:言語を見つけました(Scala以外):それはFAN(http://www.fandev.org/)で、非常に興味深いように見えますが、まだ評価する時間はありません


Scalaは、JVMまたはCLRをターゲットにするようにコンパイルして、それぞれバイトコードまたはMSILを生成できます。
Daniel Spiewak 2008

知っておくと良いのですが、DZoneを読んでいるときに1か月ほど前に別の言語を見つけました:見つけました!私の投稿の編集を参照してください
GHad 2008

1

同意しましたが、違いは初心者として理解するのに十分なほどわずかです。.Netを基本から学びたい場合は、共通言語インフラストラクチャと共通型システムを確認することをお勧めします。



1

MSILはJavaバイトコードと比較すべきではなく、「Javaバイトコードを構成する命令」と比較すべきだと思います。

逆アセンブルされたJavaバイトコードの名前はありません。「Javaバイトコード」は、公式文書でその名前が見つからないため、非公式のエイリアスである必要があります。 Javaクラスファイル逆アセンブラは言う

クラス内の各メソッドについて、逆アセンブルされたコード、つまりJavaバイトコードを構成する命令を出力します。これらは、Java仮想マシン仕様に記載されています。

「JavaVM命令」と「MSIL」はどちらも、人間が読める形式ではない.NETバイトコードとJavaコードにアセンブルされます。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.