Подтвердить что ты не робот

Почему нужны виртуальные машины?

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

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

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

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

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

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

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

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

4b9b3361

Ответ 1

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

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

Таким образом, после компиляции они связаны с машиной (X86, набор инструкций и архитектуры Intel и amd) и ОС.

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

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

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

Контрастность с .NET.

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

Вдруг вы можете написать один конкретный эмулятор компьютера для любого процессора, на котором вы хотите запустить .NET, а затем на нем может работать любая программа .NET. Не нужно беспокоиться о ОС или базовой архитектуре процессора - если есть .NET VM, то программное обеспечение будет работать.

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

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

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

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

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

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

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

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

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

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

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

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

-Adam

Ответ 2

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

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

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

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

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

CLR также предлагает вам защиту кода.

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

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

Ответ 3

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

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

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

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

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

Ответ 4

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

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

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

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

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

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

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

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

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

Ответ 5

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

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

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

Ответ 6

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

Ответ 7

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

Mono

Ответ 8

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

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

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

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

Ответ 9

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

Ответ 10

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