Различия между байт-кодом MSIL и Java?

Ответы:

75

Прежде всего позвольте мне сказать, что я не думаю, что тонкие различия между байт-кодом Java и MSIL - это то, что должно беспокоить начинающего разработчика .NET. Оба они служат одной и той же цели - определить абстрактную целевую машину, которая является уровнем выше физической машины, используемой в конечном итоге.

Байт-код MSIL и Java очень похож, на самом деле есть инструмент под названием Grasshopper, который переводит MSIL в байт-код Java, я был частью команды разработчиков Grasshopper, поэтому я могу поделиться своими (блеклыми) знаниями. Обратите внимание, что я перестал работать над этим, когда вышла .NET framework 2.0, поэтому некоторые из этих вещей могут больше не соответствовать действительности (если да, оставьте комментарий, и я исправлю его).

  • .NET допускает определенные пользователем типы, которые имеют семантику значений в отличие от семантики обычных ссылок ( struct).
  • .NET поддерживает беззнаковые типы, что делает набор инструкций немного богаче.
  • Java включает в байт-код спецификацию исключений для методов. Хотя спецификация исключения обычно применяется только компилятором, она может быть реализована JVM, если используется загрузчик классов, отличный от используемого по умолчанию.
  • Дженерики .NET выражаются в языке IL, в то время как дженерики Java используют только стирание типов .
  • Атрибуты .NET не имеют эквивалента в Java (правда ли это?).
  • .NET enums- это не более чем оболочки для целых типов, в то время как Javaenums - в значительной степени полноценные классы (спасибо Internet Friend за комментарии).
  • .NET имеет outи refпараметры.

Существуют и другие языковые различия, но большинство из них не выражаются на уровне байтового кода, например, если память обслуживает не staticвнутренние классы Java (которые не существуют в .NET) не являются функцией байт-кода, компилятор генерирует дополнительный аргумент для конструктор внутреннего класса и передает внешний объект. То же верно и для лямбда-выражений .NET.

Мотти
источник
Что касается атрибутов - аннотации Java также могут отображаться в байт-коде, так что есть эквивалент.
Дуб
@Oak: аннотации Java позволяют передавать только данные, в то время как атрибуты .NET - это полностью работающие классы, которые могут иметь логику и, что наиболее важно, реализовывать интерфейсы.
Федор Сойкин
Байт-код также имеет отдельные инструкции возврата для каждого типа возвращаемого типа, не знаю, действительно ли это помогает в безопасности типов.
Сесил Посудомоечная машина
1
Тот факт, что типы значений в .NET могут иногда выделяться в стеке, имеет тривиальное значение по сравнению с тем фактом, что они имеют семантику значений ; каждое место хранения значений типа является экземпляром. Напротив, каждое место хранения в Java является либо примитивной, либо беспорядочной ссылкой на объект; других видов нет.
supercat
1
Интересно, как они сравнивают производительность? MSIL быстрее интерпретирует, чем байт-код, например?
Люк Т О'Брайен,
23

CIL (собственное имя для MSIL) и байт-код Java больше похожи, чем различны. Однако есть несколько важных отличий:

1) CIL с самого начала разрабатывался как целевой для нескольких языков. Таким образом, он поддерживает гораздо более богатую систему типов, включая подписанные и беззнаковые типы, типы значений, указатели, свойства, делегаты, события, универсальные типы, объектную систему с одним корнем и многое другое. CIL поддерживает функции, которые не требуются для исходных языков CLR (C # и VB.NET), такие как глобальные функции и оптимизация хвостового вызова . Для сравнения, байт-код Java был разработан как цель для языка Java и отражает многие ограничения, обнаруженные в самой Java. Было бы намного сложнее написать C или схему с использованием байт-кода Java.

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 для 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 в любом текстовом редакторе.

Вы также можете скомпилировать указанную выше программу 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Выход не компилируется (насколько мне известно) , но если сравнить его с выходом КСС выше вы можете видеть , что два очень похожи.

Джастин
источник
2
Оказывается, были попытки создать читаемый / записываемый язык ассемблера Java. Два, которые я нашел, - это Jasmin и Java Bytecode Assembler
Джастин
2
Я написал здесь, что намного лучше. В отличие от Jasmin, он разработан, чтобы иметь возможность дизассемблировать и повторно собирать любой допустимый файл класса. github.com/Storyyeller/Krakatau . Я думаю, было бы правильнее сказать, что Microsoft предоставляет стандартный ассемблер, в то время как программисты Java должны создавать свои собственные.
Сурьма
22

По сути, они делают то же самое, MSIL - это версия байт-кода Java от Microsoft.

Основные внутренние отличия:

  1. Байт-код был разработан как для компиляции, так и для интерпретации, в то время как MSIL был разработан специально для JIT-компиляции.
  2. MSIL был разработан для поддержки нескольких языков (C # и VB.NET и т. Д.) По сравнению с байт-кодом, написанным только для Java, в результате чего байт-код более похож на Java синтаксически, чем IL для любого конкретного языка .NET.
  3. MSIL имеет более четкое разграничение между типами значений и ссылками.

Намного больше информации и подробное сравнение можно найти в этой статье К. Джона Гофа (постскриптум).

Гай Старбак
источник
«1. Байт-код был разработан как для компиляции, так и для интерпретации, в то время как MSIL был разработан специально для JIT-компиляции» - здесь говорится о том, как Java-код компилируется в байт-код И этот байт-код интерпретируется. Я прав? MSIL не интерпретируется для выполнения?
Абдул
2

CIL, также известный как MSIL, предназначен для чтения человеком. Байт-кода Java нет.

Думайте о байт-коде Java как о машинном коде для оборудования, которое не существует (но которое эмулирует JVM).

CIL больше похож на язык ассемблера - в одном шаге от машинного кода, но при этом удобочитаем.

тонкий
источник
Байт-код на самом деле очень удобочитаем, если у вас есть шестнадцатеричный редактор. Это довольно простой стековый язык с расширениями для прямого представления классов и методов. Я думал, что MSIL нижнего уровня (например регистры)?
Даниэль Спивак
en.wikibooks.org/wiki/… en.wikibooks.org/wiki/… Один из них - это необработанный CIL. Другой - это дизассемблированный байт-код. Байт-код может быть достаточно читабельным, если вы попробуете шестнадцатеричный код, но это не цель дизайна.
slim
"Разобранный" - действительно неправильное слово для этого. Возможно, «расшифровано». Байт-код не читается в файлах .class просто для компактности. Обратитесь к странице руководства javap, нет никакой разборки, связанной с созданием читаемого байт-кода из скомпилированного класса.
Даниэль Спивак,
2

Отличий не так уж и много. Оба являются промежуточными форматами написанного вами кода. При запуске виртуальные машины будут выполнять управляемый промежуточный язык, что означает, что виртуальная машина управляет переменными и вызовами. Есть даже язык, который я сейчас не помню, который может работать в .Net и Java одинаково.

По сути, это просто другой формат для того же

Изменить: нашел язык (кроме Scala): это FAN ( http://www.fandev.org/ ), выглядит очень интересно, но пока нет времени для оценки

GHad
источник
Scala может быть скомпилирован для работы с JVM или CLR, генерируя байт-код или MSIL соответственно.
Даниэль Спивак,
Приятно знать, но я нашел другой язык около месяца назад, когда читал DZone: Нашел! См. Редактирование моего сообщения
GHad
1

Согласитесь, различия достаточно малы, чтобы их усвоить новичок. Если вы хотите изучить .Net, начиная с основ, я бы рекомендовал взглянуть на Common Language Infrastructure и Common Type System.

Интернет-друг
источник
1

Серж Лидин написал достойную книгу о деталях MSIL: Expert .NET 2.0 IL Assembler . Я также смог быстро освоить MSIL, просмотрев простые методы с помощью .NET Reflector и Ildasm (Tutorial) .

Концепции между байт-кодом MSIL и Java очень похожи.

Джеффри ЛеКурс
источник
1

Я думаю, что MSIL следует сравнивать не с байт-кодом Java, а с «инструкцией, составляющей байт-коды Java».

Нет названия дизассемблированного байт-кода java. "Java Bytecode" должен быть неофициальным псевдонимом, поскольку я не могу найти его название в официальном документе. Дизассемблер файлов классов Java говорит

Распечатывает дизассемблированный код, т. Е. Инструкции, составляющие байт-коды Java, для каждого из методов класса. Они задокументированы в Спецификации виртуальной машины Java.

И «инструкции Java VM», и «MSIL» собраны в байт-код .NET и Java-код, которые не читаются человеком.

Деннис С
источник