Вопрос

Я читал этот вопрос чтобы выяснить различия между виртуальной машиной Java и .NET CLR, ответ Бенджи заставил меня задуматься, зачем вообще нужны виртуальные машины.

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

Но, если это так, то чего я не понимаю, так это почему C или C ++-код, скомпилированный в машинный код, может выполняться на любом компьютере, если это правильная ОС.Почему тогда программа на C, которую я скомпилировал на своем компьютере с Windows, используя Pentium, могла бы запускаться на другом моем компьютере с Windows, используя AMD?

Если C-код может выполняться на любом процессоре, то какова цель виртуальной машины?Это значит, что один и тот же код может быть запущен на любой ОС?Я знаю, что Java имеет версии виртуальных машин практически для любой ОС, но есть ли среда CLR для других ОС, кроме Windows?

Или есть что-то еще, чего я не понимаю?Выполняет ли ОС какую-то другую интерпретацию ассемблерного кода, который она запускает, чтобы адаптировать его к конкретному процессору или что-то в этом роде?

Мне очень любопытно, как все это работает, поэтому я был бы очень признателен за четкое объяснение.

Примечание:Причина, по которой я не просто разместил свои запросы в виде комментариев в JVM vs.Вопрос CLR заключается в том, что у меня пока недостаточно баллов для публикации комментариев = b.

Редактировать:Спасибо за все замечательные ответы!Итак, кажется, чего мне не хватало, так это того, что, хотя все процессоры имеют различия, существует общая стандартизация, в первую очередь архитектуры X86, которая обеспечивает достаточно большой набор общих функций, так что код C, скомпилированный на одном процессоре X86, будет работать по большей части на другом процессоре X86.Это еще раз подтверждает правоту виртуальных машин, не говоря уже о том, что я забыл о важности сборки мусора.

Это было полезно?

Решение

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

Компиляторы C и C ++ компилируются в машинный код с заголовками, соответствующими операционной системе, на которую они нацелены.После компиляции они перестают каким-либо образом ассоциироваться с языком, на котором они были скомпилированы, и являются просто двоичными исполняемыми файлами.(есть артефакты, которые могут показать, с какого языка он был скомпилирован, но дело здесь не в этом)

Таким образом, после компиляции они ассоциируются с машиной (X86, набором инструкций intel и amd и архитектурой) и операционной системой.

Вот почему они могут запускаться на любой совместимой машине x86 и любой совместимой ОС (win95 через winvista для некоторых программ).

Однако они не могут запускаться на компьютере с OSX, даже если он работает на процессоре Intel - двоичный файл несовместим, если вы не используете дополнительное программное обеспечение для эмуляции (например, parallels или виртуальную машину с Windows).

Кроме того, если вы хотите запустить их на процессоре ARM, или MIPS, или PowerPC, то вам нужно запустить эмулятор с полным набором машинных команд, который интерпретирует двоичный машинный код с X86 на любой машине, на которой вы его запускаете.

Сравните это с .NET.

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

Внезапно вы можете написать один эмулятор конкретной машины для любого процессора, который вы хотите запустить .Включите NET, и тогда ЛЮБАЯ программа .NET сможет работать на нем.Не нужно беспокоиться об операционной системе или базовой архитектуре процессора - если есть виртуальная машина .NET, то программное обеспечение будет запущено.

Но давайте пойдем немного дальше - раз у вас есть этот общий язык, почему бы не создать компиляторы, которые преобразуют в него любой другой письменный язык?

Итак, теперь у вас может быть компилятор C, C #, C ++, Java, javascript, Basic, python, lua или любого другого языка, который преобразует написанный код так, чтобы он выполнялся на этой виртуальной машине.

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

Если вам все еще интересно, почему это хорошо, рассмотрите ранние версии DOS-компьютеров и то, что Microsoft реальный вклад в развитие мира был:

Autocad должен был написать драйверы для каждого принтера, на котором они могли печатать.Как и lotus 1-2-3.На самом деле, если вы хотели, чтобы ваше программное обеспечение печатало, вам нужно было написать свои собственные драйверы.Если бы было 10 принтеров и 10 программ, то 100 различных фрагментов по существу одного и того же кода должны были быть написаны отдельно и независимо.

Чего пыталась достичь Windows 3.1 (наряду с GEM и многими другими уровнями абстракции), так это сделать так, чтобы производитель принтера написал один драйвер для своего принтера, а программист написал один драйвер для класса Windows printer.

Теперь, имея 10 программ и 10 принтеров, нужно написать всего 20 фрагментов кода, а поскольку часть кода Microsoft была одинаковой для всех, то примеры из MS означали, что вам оставалось очень мало работы.

Теперь программа была ограничена не только 10 принтерами, которые они выбрали для поддержки, но и всеми принтерами, производители которых предоставили драйверы для Windows.

Та же проблема возникает и при разработке приложений.Есть действительно удобные приложения, которые я не могу использовать, потому что я не пользуюсь MAC.Существует масса дубликатов (сколько текстовых процессоров мирового класса нам действительно нужно?).

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

.NET ближе, но никто не разрабатывает виртуальные машины мирового класса для платформ, отличных от Windows (mono так близко...и все же не совсем там).

Итак...Вот почему нам нужны виртуальные машины.Потому что я не хочу ограничивать себя небольшой аудиторией просто потому, что они выбрали комбинацию ОС / компьютера, отличную от моей.

-Адам

Другие советы

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

Однако у процессоров есть определенные общие черты, например, процессоры Intel x86 и AMD обладают достаточно большим набором свойств, так что большая часть кода, скомпилированного для одного, будет выполняться на другом.Однако, если вы хотите использовать свойства, зависящие от процессора, то вам нужен компилятор или набор библиотек, которые сделают это за вас.

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

Наиболее заметной предлагаемой услугой является вывоз мусора, предлагаемый CLR и JVM.Обе эти виртуальные машины предлагают вам эту услугу бесплатно.Они управляют памятью за вас.

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

Среда CLR также предлагает вам определенную форму защиты кода.

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

Вы могли бы получить некоторые из них, используя библиотеки, но тогда это вынуждает вас использовать шаблон использования библиотеки, тогда как в службах .NET и Java, которые предлагаются вам через CLR и JVM, доступ к ним согласован.

По сути, это допускает "управляемый код", что означает именно то, что там сказано - виртуальная машина управляет кодом во время его выполнения.Три основных преимущества этого - своевременная компиляция, управляемая сборка указателей / мусора и контроль безопасности.

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

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

Безопасность не требует пояснений: виртуальная машина останавливает код от выполнения того, чего он не должен делать, потому что он наблюдает.Лично я думаю, что это, вероятно, главная причина, по которой Microsoft выбрала управляемый код для C #.

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

Большинство компиляторов, даже компиляторы машинного кода, используют какой-то промежуточный язык.

В основном это делается для снижения затрат на создание компилятора.В мире существует много (N) языков программирования.В мире также существует множество (M) платформ аппаратного обеспечения.Если бы компиляторы работали без использования промежуточного языка, общее количество "компиляторов", которые необходимо было бы написать для поддержки всех языков на всех аппаратных платформах, составило бы N * M.

Однако, определив промежуточный язык и разбив компилятор на 2 части, интерфейс и серверную часть, при этом интерфейс компилирует исходный код в IL, а серверная часть компилирует IL в машинный код, вам может сойти с рук написание только N + M компиляторов.В конечном итоге это приводит к огромной экономии средств.

Большая разница между компиляторами CLR / JVM и компиляторами машинного кода заключается в том, как интерфейсный и серверный компиляторы связаны друг с другом.В компиляторе машинного кода два компонента обычно объединяются в один исполняемый файл, и оба запускаются, когда программист нажимает "build" в IDE.

В компиляторах CLR / JVM интерфейс и серверная часть выполняются в разное время.Внешний интерфейс запускается во время компиляции, создавая IL, который фактически отправляется клиентам.Затем серверная часть воплощается в отдельном компоненте, который вызывается во время выполнения.

Итак, возникает альтернативный вопрос: "Каковы преимущества отсрочки серверной компиляции до времени выполнения"?

Ответ таков:"Это зависит".

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

Однако есть и недостатки.Анализ, необходимый для реализации обширной оптимизации компилятора, может быть дорогостоящим.Это означает, что серверные части "JIT" часто выполняют меньше оптимизаций, чем исходные серверные части.Это может ухудшить производительность.Кроме того, необходимость вызывать компилятор во время выполнения также увеличивает время, необходимое для загрузки программ.Программы, созданные с помощью "предварительных" компиляторов, не имеют этих проблем.

Во-первых, машинный код - это не самая низкая форма инструкций для центрального процессора.Современные процессоры x86 сами интерпретируют набор команд X86 в другой внутренний формат, используя микрокод.Единственные люди, которые на самом деле программируют микрокод, - это инженеры-разработчики чипов, которые добросовестно и безболезненно эмулируют устаревший чип команд x86 для достижения максимальной производительности с использованием современных технологий.

Типы разработчиков всегда добавляли дополнительные уровни абстракций из-за мощи и возможностей, которые они предоставляют.В конце концов, улучшенные абстракции позволяют писать новые приложения быстрее и надежнее.Компаниям наплевать на то, что или как выглядит их код, они просто хотят, чтобы работа выполнялась надежно и быстро.Действительно ли имеет значение , если версия приложения на C занимает на несколько миллисекунд меньше , но в конечном итоге разработка занимает вдвое больше времени ?

Вопрос скорости почти не является аргументом, поскольку многие корпоративные приложения, обслуживающие миллионы людей, написаны на платформах / языках, таких как java - например, GMail, GMaps.Забудьте о том, какой язык / платформа является самой быстрой.Что еще более важно, так это то, что вы используете правильные алгоритмы, пишете эффективный код и выполняете свою работу.

Процессоры AMD и Intel имеют архитектуру x86, если вы хотите запустить программу на c / c ++ на другой архитектуре, вам придется использовать компилятор для этой архитектуры, один и тот же двоичный исполняемый файл не будет выполняться на разных архитектурах процессора.

Я знаю, что Java имеет версии виртуальных машин практически для любой ОС, но есть ли среда CLR для других ОС, кроме Windows?

Моно

В очень упрощенном виде это связано с тем, что Intel и AMD реализуют один и тот же язык ассемблера, с одинаковым количеством регистров и т.д. И т.п...

Итак, ваш компилятор C компилирует код для работы в Linux.Эта сборка использует Linux ABI, так что до тех пор, пока программа компиляции выполняется в Linux, на сборке x86 и с правильной сигнатурой функции, все в порядке.

Теперь попробуйте взять этот скомпилированный код и установить его, скажем, в Linux / PPC (напримерLinux на старой iBook).Это не сработает.Где как программа Java будет, потому что JVM была реализована на платформе Linux / PPC.

Язык ассемблера в настоящее время - это, по сути, еще один интерфейс, на котором программист может программировать.x86 (32-разрядная версия) позволяет получить доступ к eax, ebx, ecx, edx для регистров целых чисел общего назначения и f00-f07 для регистров с плавающей запятой.За кулисами у процессора на самом деле есть еще сотня регистров, и он перемешал все это, чтобы снизить производительность.

Вы правы в своем анализе, java или C # могли бы быть разработаны для прямой компиляции для запуска на любой машине, и, вероятно, было бы быстрее, если бы они это сделали.Но подход виртуальной машины дает полный контроль над средой, в которой выполняется ваш код, виртуальная машина создает безопасную изолированную среду, которая позволяет только командам с надлежащим доступом безопасности выполнять потенциально опасный код - например, менять пароль или обновлять загрузочный сектор HD.Есть много других преимуществ, но это главная причина.Вы не можете получить StackOverflow в C # ...

Я думаю, что предпосылка вашего вопроса верна - вы, конечно, не первый, кто задает этот вопрос.Так что проверьте http://llvm.org чтобы увидеть альтернативный подход (который сейчас является запущенным проектом?или спонсируется Apple)

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top