Виртуальная машина Java и среда CLR

141

Как своего рода продолжение вопроса под названием « Различия между байт-кодом MSIL и Java»? , каковы (основные) различия или сходства в том, как работает виртуальная машина Java, по сравнению с тем, как.NET Framework Common Language Runtime (CLR) работает?

Кроме того, .NET Framework CLR - это «виртуальная машина» или у нее нет атрибутов виртуальной машины?

Франк V
источник
Что ж, если вы сравниваете подобное и подобное, вам следует переформулировать вопрос как разницу между виртуальной машиной и CLR (Common Language Runtime), которая является прямым аналогом виртуальной машины.
cletus

Ответы:

281

Между обеими реализациями много общего (и, на мой взгляд: да, они обе «виртуальные машины»).

Во-первых, это виртуальные машины на основе стека, без понятия «регистры», как мы привыкли видеть в современных процессорах, таких как x86 или PowerPC. Оценка всех выражений ((1 + 1) / 2) выполняется путем помещения операндов в «стек» и последующего извлечения этих операндов из стека всякий раз, когда инструкция (сложение, деление и т. Д.) Требует использования этих операндов. Каждая инструкция помещает свои результаты обратно в стек.

Это удобный способ реализовать виртуальную машину, потому что почти каждый процессор в мире имеет стек, но количество регистров часто отличается (а некоторые регистры являются специальными, и каждая инструкция ожидает своих операндов в разных регистрах и т. ).

Итак, если вы собираетесь моделировать абстрактную машину, модель, основанная исключительно на стеке, - довольно хороший способ.

Конечно, настоящие машины так не работают. Таким образом, JIT-компилятор отвечает за выполнение «регистрации» операций с байт-кодом, по сути планируя фактические регистры ЦП для хранения операндов и результатов, когда это возможно.

Итак, я думаю, что это одна из самых общих черт между CLR и JVM.

Что до отличий ...

Одно интересное различие между двумя реализациями заключается в том, что среда CLR включает инструкции для создания универсальных типов, а затем для применения параметрических специализаций к этим типам. Итак, во время выполнения CLR считает List <int> совершенно другим типом, нежели List <String>.

Внутри него используется один и тот же MSIL для всех специализаций ссылочного типа (так что List <String> использует ту же реализацию, что и List <Object>, с разными типами на границах API), но каждый тип значения использует собственная уникальная реализация (List <int> генерирует совершенно отличный от List <double> код).

В Java универсальные типы - это просто уловка компилятора. JVM не знает, какие классы имеют аргументы типа, и не может выполнять параметрическую специализацию во время выполнения.

С практической точки зрения это означает, что вы не можете перегружать методы Java универсальными типами. У вас не может быть двух разных методов с одним и тем же именем, различающихся только тем, принимают ли они List <String> или List <Date>. Конечно, поскольку CLR знает о параметрических типах, у нее нет проблем с обработкой методов, перегруженных специализациями универсальных типов.

В повседневной жизни я больше всего замечаю разницу между CLR и JVM.

Другие важные отличия включают:

  • В CLR есть замыкания (реализованные как делегаты C #). JVM поддерживает закрытие только с Java 8.

  • В CLR есть сопрограммы (реализованные с помощью ключевого слова yield в C #). JVM этого не делает.

  • CLR позволяет пользовательскому коду определять новые типы значений (структуры), тогда как JVM предоставляет фиксированный набор типов значений (byte, short, int, long, float, double, char, boolean) и позволяет пользователям определять только новые ссылки - виды (классы).

  • CLR обеспечивает поддержку объявления указателей и управления ими. Это особенно интересно, потому что как JVM, так и CLR используют реализации сборщика мусора со строгим сжатием поколений в качестве стратегии управления памятью. В обычных обстоятельствах сборщик мусора со строгим уплотнением действительно испытывает трудности с указателями, потому что, когда вы перемещаете значение из одного места в памяти в другое, все указатели (и указатели на указатели) становятся недействительными. Но CLR предоставляет механизм «закрепления», чтобы разработчики могли объявить блок кода, внутри которого CLR не разрешено перемещать определенные указатели. Это очень удобно.

  • Самая большая единица кода в JVM - это либо «пакет», о чем свидетельствует ключевое слово «protected», либо, возможно, JAR (т.е. Java ARchive), о чем свидетельствует возможность указать jar-файл в пути к классам и обработать его как папку кода. В среде CLR классы объединены в «сборки», а среда CLR предоставляет логику для анализа сборок и управления ими (которые загружаются в «домены приложений», предоставляя «песочницы» уровня приложения для выделения памяти и выполнения кода).

  • Формат байт-кода CLR (состоящий из инструкций и метаданных MSIL) имеет меньше типов инструкций, чем JVM. В JVM каждая уникальная операция (добавление двух значений int, добавление двух значений с плавающей запятой и т. Д.) Имеет свою собственную уникальную инструкцию. В среде CLR все инструкции MSIL полиморфны (складываются два значения), а JIT-компилятор отвечает за определение типов операндов и создание соответствующего машинного кода. Однако я не знаю, какая стратегия предпочтительнее. У обоих есть компромиссы. JIT-компилятор HotSpot для JVM может использовать более простой механизм генерации кода (ему не нужно определять типы операндов, потому что они уже закодированы в инструкции), но это означает, что ему нужен более сложный формат байт-кода, с большим количеством типов инструкций.

Я использую Java (и восхищаюсь JVM) уже около десяти лет.

Но, на мой взгляд, CLR теперь является лучшей реализацией почти во всех отношениях.

Benjismith
источник
73
Замыкания и генераторы реализованы на уровне языка и просто представлены как классы на уровне CLR.
Курт Хагенлохер,
2
А как насчет различий в том, как они обрабатывают кучу? CLR больше зависит от процесса ОС / хоста, в то время как JVM более или менее полностью управляет памятью кучи.
Келли С. Френч
6
Важное различие заключается в контрасте между JVM-компиляцией (CLR) и адаптивной оптимизацией (Oracle / Sun).
Эдвин Далорцо
1
Слоты локальных переменных Java действуют во многом как регистры. Но в любом случае это спорный вопрос, поскольку JIT превращает локальные слоты и стек в реальные регистры.
Antimony
1
@kuhajeyan это потому, что когда был представлен CLR, JVM было 10 лет. это давно в IT. Когда в 1993 году появилась JVM, у нее не было серьезных соперников, для CLR (2003) была зрелая и надежная JVM с прочной опорой в отрасли.
Simple Fellow
25

Ваш первый вопрос - это сравнение JVM с .NET Framework - я полагаю, вы действительно хотели вместо этого сравнить с CLR. Если так, я думаю, вы могли бы написать небольшую книгу об этом ( РЕДАКТИРОВАТЬ: похоже, у Бенджи уже есть :-)

Одно важное отличие состоит в том, что среда CLR разработана как независимая от языка архитектура, в отличие от JVM.

Еще одно важное отличие состоит в том, что среда CLR была специально разработана для обеспечения высокого уровня взаимодействия с машинным кодом. Это означает, что среда CLR должна управлять надежностью и безопасностью при доступе к собственной памяти и ее модификации, а также управлять маршалингом между структурами данных на основе CLR и собственными структурами данных.

Чтобы ответить на ваш второй вопрос, термин «виртуальная машина» - это более старый термин из мира оборудования (например, виртуализация IBM 360 в 1960-х годах), который раньше означал программную / аппаратную эмуляцию базовой машины для выполнения такого же рода то, что делает VMWare.

CLR часто называют «механизмом выполнения». В данном контексте это реализация IL-машины поверх x86. Это также то, что делает JVM, хотя вы можете утверждать, что существует важное различие между полиморфными байт-кодами CLR и типизированными байт-кодами JVM.

Итак, педантичный ответ на ваш второй вопрос - «нет». Но на самом деле все сводится к тому, как вы определяете эти два термина.

РЕДАКТИРОВАТЬ: Еще одно различие между JVM и CLR заключается в том, что JVM (версия 6) очень неохотно освобождает выделенную память обратно в операционную систему, даже если это возможно.

Например, предположим, что процесс JVM запускается и изначально выделяет 25 МБ памяти из операционной системы. Затем код приложения пытается выделить ресурсы, требующие дополнительных 50 МБ. JVM выделит дополнительные 50 МБ из операционной системы. Как только код приложения перестанет использовать эту память, он будет удален, и размер кучи JVM уменьшится. Однако JVM будет освобождать выделенную память операционной системы только при определенных обстоятельствах . В противном случае в течение оставшейся части времени существования процесса эта память останется выделенной.

С другой стороны, среда CLR возвращает выделенную память обратно операционной системе, если она больше не нужна. В приведенном выше примере среда CLR освободила бы память после уменьшения размера кучи.

HTTP 410
источник
2
Абсолютно неправильно, что JVM не освобождает выделенную память. См. Мой ответ на этот вопрос в качестве доказательства: stackoverflow.com/questions/366658/…
Майкл Боргвардт
Я видел, как JVM возвращает память обратно в Windows.
Стив Куо,
Я изменил свой ответ, чтобы сказать, что JVM 6 очень неохотно освобождает память, со ссылками на ответы Рана и Майкла. Я никогда не видел такого поведения с JVM 5, так что, возможно, эта версия была еще более неохотной.
HTTP 410,
Не могли бы вы рассказать, как JVM активно управляет кучей, в то время как CLR полагается на родительский процесс? Конкретный пример, который я использую, - JVM имеет аргументы времени выполнения для максимального размера кучи, а среда CLR по умолчанию - нет. Хотя верно, что приложение CLR, размещенное в IIS, может настроить IIS для ограничения памяти, это будет означать включение IIS в определение виртуальной машины.
Келли С. Френч
@ Стив Куо, да, я тоже это видел. обычно с 17:00 до 18:00.
Simple Fellow
11

CLR и JVM являются виртуальными машинами.

.NET Framework и среда выполнения Java представляют собой объединение соответствующих виртуальных машин и их библиотек. Без библиотек виртуальные машины бесполезны.

Аллен Лалонд
источник
11

Более подробную информацию о различиях можно найти в различных академических и частных источниках. Хорошим примером является выбор дизайна CLR .

Вот некоторые конкретные примеры:

  • Некоторые операнды низкого уровня имеют типизированный тип, например "добавить два целых числа", где, поскольку CLR использует полиморфный операнд. (т.е. fadd / iadd / ladd vs просто добавить)
  • В настоящее время JVM выполняет более агрессивное профилирование и оптимизацию во время выполнения (например, Hotspot). В настоящее время CLR выполняет оптимизацию JIT, но не оптимизацию времени выполнения (т.е. заменяет код во время работы).
  • CLR не встраивает виртуальные методы, JVM делает ...
  • Поддержка типов значений в CLR помимо «примитивов».
Джеймс Шек
источник
-11

Это не виртуальная машина, платформа .net компилирует сборки в собственный двоичный файл во время первого запуска:

В вычислениях JIT-компиляция, также известная как динамическая трансляция, представляет собой метод повышения производительности компьютерной программы во время выполнения. JIT основывается на двух предыдущих идеях в средах выполнения: компиляция байт-кода и динамическая компиляция. Он преобразует код во время выполнения перед его выполнением изначально, например байт-код в собственный машинный код. Повышение производительности по сравнению с интерпретаторами связано с кэшированием результатов преобразования блоков кода, а не просто с переоценкой каждой строки или операнда каждый раз, когда она встречается (см. «Интерпретируемый язык»). Он также имеет преимущества перед статической компиляцией кода во время разработки, так как может перекомпилировать код, если это окажется полезным, и может обеспечить гарантии безопасности.

Некоторые современные среды выполнения, такие как Microsoft .NET Framework, большинство реализаций Java и совсем недавно ActionScript 3, полагаются на JIT-компиляцию для высокоскоростного выполнения кода.

Источник: http://en.wikipedia.org/wiki/Just-in-time_compilation

Добавление .NET framework содержит виртуальную машину, как и Java.

Дионес
источник
10
Тот факт, что виртуальная машина использует JIT для оптимизации производительности, не означает, что это больше не виртуальная машина. Когда программист компилирует, он компилирует в виртуальную машину, оставляя реализацию для выполнения выполнения, как он считает нужным
Аллен Лалонд