私は.Netを初めて使用し、最初に基本を理解しようとしています。MSILとJavaバイトコードの違いは何ですか?
私は.Netを初めて使用し、最初に基本を理解しようとしています。MSILとJavaバイトコードの違いは何ですか?
回答:
まず最初に、JavaバイトコードとMSILの微妙な違いは、初心者の.NET開発者を悩ませるべきものではないと思います。これらは両方とも、最終的に使用される物理マシンの上のレイヤーである抽象的なターゲットマシンを定義するという同じ目的を果たします。
MSILとJavaバイトコードは非常に似ています。実際、MSILをJavaバイトコードに変換するGrasshopperというツールがあります。私はGrasshopperの開発チームの一員だったので、(色あせた)知識を少し共有できます。.NET Framework 2.0がリリースされたときにこれに取り組むのをやめたので、これらのいくつかはもう真実ではないかもしれないことに注意してください(もしそうなら、コメントを残してください、そして私はそれを修正します)。
struct
)に加えて、値セマンティクスを持つユーザー定義型を使用できます。enums
は整数型のラッパーにすぎませんが、Javaenums
はほぼ本格的なクラスです(コメントしてくれたInternet Friendに感謝します)。out
ありref
ます。他の言語の違いはありますが、それらのほとんどはバイトコードレベルで表現されていません。たとえば、メモリがJavaの非static
内部クラス(.NETには存在しない)を提供する場合、バイトコード機能ではない場合、コンパイラは次の追加の引数を生成します。内部クラスのコンストラクターであり、外部オブジェクトを渡します。同じことが.NETラムダ式にも当てはまります。
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は非常に似ていることがわかります。
彼らは本質的に同じことをしています。MSILはMicrosoftのバージョンのJavaバイトコードです。
内部の主な違いは次のとおりです。
K John Goughによるこの記事(追記文書)には、さらに多くの情報と詳細な比較が記載されています。
CIL(別名MSIL)は、人間が読める形式にすることを目的としています。Javaバイトコードはそうではありません。
Javaバイトコードは、存在しない(ただし、JVMがエミュレートする)ハードウェアのマシンコードであると考えてください。
CILは、アセンブリ言語に似ています。人間が読める形式でありながら、機械語から1ステップです。
それほど大きな違いはありません。どちらも、作成したコードの中間形式です。実行されると、仮想マシンは管理対象の中間言語を実行します。つまり、仮想マシンが変数と呼び出しを制御します。.NetとJavaで同じように実行できる、今は覚えていない言語もあります。
基本的に、それは同じことのための単なる別のフォーマットです
編集:言語を見つけました(Scala以外):それはFAN(http://www.fandev.org/)で、非常に興味深いように見えますが、まだ評価する時間はありません
同意しましたが、違いは初心者として理解するのに十分なほどわずかです。.Netを基本から学びたい場合は、共通言語インフラストラクチャと共通型システムを確認することをお勧めします。
Serge Lidinは、MSILの詳細に関するまともな本を執筆しました:Expert .NET 2.0 ILAssembler 。また、.NET ReflectorとIldasm(Tutorial)を使用した簡単な方法を調べることで、MSILをすばやく取得することができました。
MSILとJavaバイトコードの概念は非常に似ています。
MSILはJavaバイトコードと比較すべきではなく、「Javaバイトコードを構成する命令」と比較すべきだと思います。
逆アセンブルされたJavaバイトコードの名前はありません。「Javaバイトコード」は、公式文書でその名前が見つからないため、非公式のエイリアスである必要があります。 Javaクラスファイル逆アセンブラは言う
クラス内の各メソッドについて、逆アセンブルされたコード、つまりJavaバイトコードを構成する命令を出力します。これらは、Java仮想マシン仕様に記載されています。
「JavaVM命令」と「MSIL」はどちらも、人間が読める形式ではない.NETバイトコードとJavaコードにアセンブルされます。