Что это — интерпретатор, и где он используется?
Содержание:
- Введение в .Net и c Sharp
- Преимущества и недостатки
- Как это работает?
- Примечание по байт-коду
- Примечания
- Недостатки
- Разница между компилятором и интерпретатором
- Обработка переменных
- Грамматика языка
- Что такое компиляторы и интерпретаторы?
- Природа интерпретатора
- Основы
- Интерпретатор C / C++ Ch Embeddable (стандартная версия)
- Классификация трансляторов
- За и против
- Сравнительная таблица
- Работа с памятью
- Классификация разных типов компиляторов
- Заключение
- Вывод
Введение в .Net и c Sharp
Программист пишет программу на языке, понятном программисту, а компьютер исполняет только программы, написанные на языке машинных кодов. Совокупность средств написания, редактирования и преобразования программы в машинные коды и ее исполнения называют средой разработки.
Среда разработки содержит:
-
Текстовый редактор для ввода и корректировки текста программы
-
Компилятор для перевода программы на язык машинных команд
-
Средства отладки и запуска программы на исполнение
-
Общие библиотеки с многократно используемыми программными элементами
-
Справочную систему и др.
Платформа .NET («дот нет»), разработанная компанией Microsoft, включает не только среду разработки для нескольких языков программирования, называемую Visual Studio .NET, но множество других средств, таких как средства поддержки баз данных, электронной почты и др.
Важнейшими задачами при разработке современных программных средств являются:
-
Переносимость-возможность исполнения на разных типах компьютерах
-
Безопасность – невозможность несанкционированных действий
-
Надежность – безотказность работы в заданных условиях
-
Использование готовых компонентов для ускорения разработки
-
Межъязыковое взаимодействие – применение нескольких языков программирования.
Все эти задачи решают в рамках платформы .NET.
Для обеспечения переносимости компиляторы платформы переводят программу не в машинный код, а в промежуточный язык MSIL (Microsoft Intermediate Language) или просто в IL. IL не содержит команд, зависящих от операционной системы или типа компьютера. Программу на IL исполняет среда выполнения CLR (Common Language Runtime), которая уже специфична для каждого типа компьютера. Перевод IL-программы в машинные коды конкретного компьютера выполняет JIT (Just In Time) –компилятор.
Схема выполнения программы на платформе .NET приведена на рис.1.
Компилятор создает сборку программы – файл с расширение .exe или .dll, который содержит IL-код. Выполнение программы организует среда CRL, которая следит за допустимостью операций, выполняет распределение и очистку памяти и обрабатывает ошибки исполнения. Это обеспечивает безопасность и надежность программ.
Платой за эти достоинства является снижение быстродействия программ и необходимость установки на компьютере .NET для исполнения готовых программ.
Итак, .NET – это платформа программирования.
C# (Си-Шарп) — это один из языков программирования платформы .NET. Он входит в Visual Studio — Visual Studio.NET (Версии 2008, 2010, 2012). Кроме C# в Visual Studio.NET входят Visual Basic.NET и Visual C++.
Преимущества и недостатки
Преимущества компилятора
- Программный код уже переведен в машинный, и, следовательно, требуется меньше времени на его исполнение.
- Файлы .exe выполняются быстрее, чем исходный код. Объектные программы сохраняются и могут быть запущены в любое время.
- Объектные программы пользователю сложнее изменить, чем исходный код.
- Компилятор проверяет исходный код на наличие синтаксических ошибок во время компиляции.
Недостатки компилятора
- Поскольку переводится вся программа, она использует гораздо больше памяти компьютера.
- При работе с компилятором невозможно изменить программу, не вернувшись к исходному коду.
- Необходимо создавать объектную программу перед окончательным исполняемым файлом. Это может занять много времени.
- Исходный код должен быть на 100% верным для создания исполняемого файла.
Преимущества интерпретатора
- Интерпретатор значительно облегчает работу с исходным кодом.
- Он переводит по одной инструкции за раз, поэтому использует минимальный объем памяти.
- Интерпретатор может связать сообщения об ошибках с выполняемой инструкцией, что может оказаться полезным в процессе отладки.
Недостатки интерпретатора
- Каждый раз, когда программа выполняется, тратится время на интерпретацию, из-за чего затягивается время исполнения.
- Интерпретируемые программы могут выполняться только на компьютерах, на которых имеются соответствующие интерпретаторы.
Как это работает?
Сначала компилятор создает программу. Он анализирует все операторы языка, чтобы проверить, правильны они или нет. Если компилятор найдет какую-нибудь ошибку, он выдаст соответствующее сообщение. Если же он не обнаружит никаких ошибок, то преобразует исходный код в машинный. Компилятор связывает различные кодовые файлы в программы, которые можно запустить (например, формата .exe). После этого запускается программа.
Интерпретатор создает программу. Он не связывает файлы и не генерирует машинный код. Происходит построчное выполнение исходных операторов во время исполнения программы.
Примечание по байт-коду
Как и в случае с машинным кодом, не все компьютеры понимают байт-код. Чтобы интерпретировать его на машиночитаемый язык, необходимо промежуточное ПО, такое как виртуальная машина, или движок (например, Javascript V8). По этой причине браузеры могут выполнять этот байт-код из интерпретатора во время вышеупомянутых 5-ти стадий с помощью движков JavaScript.
В результате возникает следующий вопрос:
Является ли JavaScript интерпретируемым языком?
Да, но не совсем. На ранних этапах JavaScript Брендан Айк создал движок JavaScript ‘SpiderMonkey’. У движка был интерпретатор, который говорил браузеру, что нужно делать. Сейчас есть не только интерпретаторы, но и компиляторы, а код не только интерпретируется, но и компилируется для оптимизации. Технически все зависит от реализации.
- Прототипирование для Vue(Opens in a new browser tab)
- Как не лажать с JavaScript. Часть 1
- JavaScript async/await: что хорошего, в чём опасность и как применять?
Перевод статьи Mano lingam: JavaScript: Under the Hood
Примечания
- Кочергин В. И. interpreter // Большой англо-русский толковый научно-технический словарь компьютерных информационных технологий и радиоэлектроники. — 2016. — ISBN 978-5-7511-2332-1.
- ГОСТ 19781-83; СТ ИСО 2382/7-77 // Вычислительная техника. Терминология: Справочное пособие. Выпуск 1 / Рецензент канд. техн. наук Ю. П. Селиванов. — М.: Издательство стандартов, 1989. — 168 с. — 55 000 экз. — ISBN 5-7050-0155-X.
- Першиков В. И., Савинков В. М. Толковый словарь по информатике / Рецензенты: канд. физ.-мат. наук А. С. Марков и д-р физ.-мат. наук И. В. Поттосин. — М.: Финансы и статистика, 1991. — 543 с. — 50 000 экз. — ISBN 5-279-00367-0.
- Борковский А. Б. Англо-русский словарь по программированию и информатике (с толкованиями). — М.: Русский язык, 1990. — 335 с. — 50 050 (доп.) экз. — ISBN 5-200-01169-3.
- Толковый словарь по вычислительным системам = Dictionary of Computing / Под ред. В. Иллингуорта и др.: Пер. с англ. А. К. Белоцкого и др.; Под ред. Е. К. Масловского. — М.: Машиностроение, 1990. — 560 с. — 70 000 (доп.) экз. — ISBN 5-217-00617-X (СССР), ISBN 0-19-853913-4 (Великобритания).
- Dave Martin. . Rexx FAQs. Дата обращения: 22 декабря 2009.
- Jeff Fox. (англ.). Thoughtful Programming and Forth. UltraTechnology. Дата обращения: 25 января 2010.
Недостатки
Недостатки интерпретируемых языков:
- Без статической проверки типов , которая обычно выполняется компилятором, программы могут быть менее надежными, поскольку проверка типов устраняет целый класс программных ошибок (хотя проверка типов кода может выполняться с помощью дополнительных автономных инструментов. См. TypeScript например)
- Интерпретаторы могут быть восприимчивы к атакам внедрения кода .
- Более медленное выполнение по сравнению с прямым выполнением машинного кода на центральном процессоре . Для повышения производительности используется метод своевременной компиляции, которая преобразует часто выполняемые последовательности интерпретируемых инструкций в машинный код хоста. JIT чаще всего сочетается с компиляцией в байтовый код, как в Java .
- Исходный код можно читать и копировать (например, JavaScript на веб-страницах) или более легко реконструировать посредством отражения в приложениях, где интеллектуальная собственность имеет коммерческое преимущество. В некоторых случаях обфускация используется как частичная защита от этого.
Разница между компилятором и интерпретатором
Как Компилятор так и Интерпретатор имеют одно предназначение — конвертировать инструкции языка высокого уровня (как C или Java) в бинарную форму, понятную компьютеру. Это программное обеспечение, используемое для запуска высокоуровневых программ и кодов выполняемых различные задачи. Для разных высокоуровневых языков разработаны специфичные компиляторы/интерпретаторы. Не смотря на то что как компилятор так и интерпретатор преследуют одну и ту же цель, они отличаются способом выполнения своей задачи, то есть конвертирования высокоуровневого языка в машинные инструкции. В этой статье мы поговорим о базовой работе обоих и выделим главные отличия между компилятором и интерпретатором.
Компилятор
Компилятор транслирует высокоуровневый язык в машинный. Когда пользователь пишет код на языке высокого уровня, таком как Java, и хочет его выполнить, то прежде чем это может быть сделано, будет использован специальный компилятор разработанный для Java. Компилятор сначала сканирует всю программу, а потом транслирует ее в машинный код, который будет выполнен компьютерным процессором, после чего будут выполнены соответствующие задачи.
На картинке показано базовое очертание процесса компиляции. Тут программа написанная на языке высокого уровня показана как «Исходный код», а сконвертированный называется «Исполняемый код».
Интерпретатор
Интерпретаторы не очень сильно отличаются от компиляторов. Они также конвертируют высокоуровневые языки в читаемые машиной бинарные эквиваленты. Каждый раз когда интерпретатор получает на выполнение код языка высокого уровня, то прежде чем сконвертировать его в машинный код, он конвертирует этот код в промежуточный язык. Каждая часть кода интерпретируется и выполняется отдельно и последовательно, и если в какой-то части будет найдена ошибка, она остановит интерпретацию кода без трансляции следующей части кода.
Очертание процесса интерпретации на картинке выше показывает, что сначала исходный код конвертируется в промежуточную форму, а затем выполняется интерпретатором.
Ниже перечислены главные отличия между компилятором и интерпретатором:
- Интерпретатор берет одну инструкцию, транслирует и выполняет ее, а затем берет следующую инструкцию. Компилятор же транслирует всю программу сразу, а потом выполняет ее.
- Компилятор генерирует отчет об ошибках после трансляции всего, в то время как интерпретатор прекратит трансляцию после первой найденной ошибки.
- Компилятор по сравнению с интерпретатором требует больше времени для анализа и обработки языка высокого уровня.
- Помимо времени на обработку и анализ, общее время выполнения кода компилятора быстрее в сравнении с интерпретатором.
Обработка переменных
- Он считывает до двух первых символов имени переменной. (Это было стандартным неудобством версий BASIC той эпохи из-за ограничений памяти.)
- По этим двум символам он определяет индекс переменной. «A» — это переменная 0, «A0» — переменная 53, и т.д. Уравнение довольно простое, но сейчас оно нас не интересует.
- BASIC продолжает сканирование в поисках символа типа переменной. Например, в BASIC обозначает строковую переменную. Тип переменной хранится парой битов выше в индексе переменной.
- Затем BASIC записывает тип и индекс в выходные данные, а потом вместе с самим именем переменной записывает длину этого имени. Именно на этом мы теряем экономию пространства!
Грамматика языка
Любая конструкция, кроме запроса статистики (это у нас как бы служебная команда) и создания функции начинается и заканчивается ключевыми словами. Благодаря этому мы можем смело расставлять как угодно переносы строк и отступы. Кроме этого (мы же работаем с русским языком) я специально создал по паре инструкций для случаев, когда надо передавать и переменную, и значение. Позже увидите, зачем это было нужно. Итак, наш файл yobaParser.mly:
%{ open YobaType %} %token <string> ID %token <int> INT %token RULEZ %token GIVE TAKE %token WASSUP DAMN %token CONTAINS THEN ELSE %token FUCKOFF %token STATS %token MEMORIZE IS %token CALL %start main %type <YobaType.action> main %% main: expr { $1 } expr: fullcommand { $1 } | MEMORIZE ID IS fullcommandlist DAMN { AddFunction($2, $4) } fullcommandlist: fullcommand { $1 :: [] } | fullcommand fullcommandlist { $1 :: $2 } fullcommand: WASSUP command DAMN { $2 } | STATS { Stats } command: FUCKOFF { DoNothing } | GIVE ID INT { Increment($3, $2) } | GIVE INT ID { Increment($2, $3) } | TAKE ID INT { Decrement($3, $2) } | TAKE INT ID { Decrement($2, $3) } | RULEZ ID { Create($2) } | CALL ID { CallFunction($2) } | CONTAINS ID INT THEN command ELSE command { Conditional($3, $2, $5, $7) } | CONTAINS INT ID THEN command ELSE command { Conditional($2, $3, $5, $7) } %%
Первым делом мы вставляем заголовок — открытие модуля YobaType, который содержит наш тип action, описанный в самом начале. Для чисел и строк, не являющихся ключевыми словами языка (переменных) мы объявляем два специальных типа, которым указываем, что именно они в себе содержат. Для каждого из ключевых слов с помощью директивы %token мы создаём тоже свой тип, который будет идентифицировать это слово в грамматике. Можно было бы указать их все хоть в одну строчку, просто такая запись группирует всё по видам инструкций. Имейте в виду, что все созданные нами токены — это именно подстановочные типы, по которым парсер грамматики определяет, что ему делать. Обозвать их можно как угодно, то, как они будут выглядеть в самом языке, мы опишем позже. Указываем, что входной точкой для грамматики является main, и что возвращать он всегда должен объект типа action — инструкцию для интерпретатора. Наконец, после двух знаков %% мы описываем саму грамматику:
- Инструкция состоит либо из команды (fullcommand), либо из создания функции.
- Функция, в свою очередь, состоит из списка команд (fullcommandlist).
- Команда бывает либо служебной (STATS), либо обычной (command), в таком случае она должна быть обёрнута в ключевые слова.
- С обычной командой всё просто, даже расписывать не буду.
В фигурных скобках мы указываем, что делать при совпадении строки с данным вариантом, при этом $N обозначает N-ный член конструкции. Например, если мы встречаем «CALL ID» (ID — это строка, не забываем), то мы создаём инструкцию CallFunction, которой в качестве параметра передаём $2 (как раз ID) — имя вызываемой функции.
Что такое компиляторы и интерпретаторы?
Статья рассчитана на пользователей, которые хотя бы немного знают о том, как устроены сети, операционные системы и языки программирования. Если вы вообще не имеете никакого представления о перечисленном, то рекомендуем почитать, ибо информация будет выглядеть достаточно сумбурно.
Для начал стоит разобраться, что же такое компилятор, ведь он буквально является основой основ. После написания кода на каком-либо языке он обязательно должен пройти стадию компиляции, т. е. сборки всех частей кода воедино. Дело в том, что проект всегда и обязательно разделяется на множество частей, каждая из которых выполняет лишь определенную роль. Будь то работа с сетью, файлами, пользователем и т. д. Такие куски кода могут быть написаны самим пользователем или взяты из стандартной библиотеки STL.
При взятии какого-либо элемента есть два варианта компиляции: автоматический и динамический. При автоматическом берутся все необходимые (включенные) библиотеки, а при динамическом — лишь выбранные части эти библиотек. Это весьма большая тема, поэтому рекомендуем прочитать про каждый способ отдельно.
Итак, все библиотеки, части кода в форме исходных файлов собраны, а что дальше? Правильно, теперь самое время заставить компьютер понимать наш код. Делается это для того, чтоб компьютер мог вообще взаимодействовать с пользователем. Промежуточным звеном между аппаратной и программной частью является полумашинный язык программирования – ассемблер, именно в этот язык интерпретатор переводит вами написанный код.
Из сказанного выше можно сказать, что интерпретатор – это определенная программа для перекодировки в полумашинный язык ассемблер. В следующей части статьи мы поговорим подробнее про современные компиляторы и интерпретаторы.
Природа интерпретатора
Интерпретаторы могут создаваться по-разному. Существуют интерпретаторы, которые читают исходную программу и не выполняют дополнительной обработки. Они просто берут определенное количество строк кода за раз и выполняют его.
Некоторые интерпретаторы выполняют собственную компиляцию, но обычно преобразуют программу байтовый код, который имеет смысл только для интерпретатора. Это своего рода псевдо машинный язык, который понимает только интерпретатор.
Такой код быстрее обрабатывается, и его проще написать для исполнителя (части интерпретатора, которая исполняет), который считывает байтовый код, а не код источника.
Есть интерпретаторы, для которых этот вид байтового кода имеет более важное значение. Например, язык программирования Java «запускается» на так называемой виртуальной машине
Она является исполняемым кодом или частью программы, которая считывает конкретный байтовый код и эмулирует работу процессора. Обрабатывая байтовый код так, как если бы процессор компьютера был виртуальным процессором.
У меня есть эмулятор для игровой приставки NIntendo. Когда я загружаю ROM-файл Dragon Warrior, он форматируется в машинный код, который понимает только процессор NES. Но если я создаю виртуальный процессор, который интерпретирует байтовый код во время работы на другом процессоре, я могу запустить Dragon Warrior на любой машине с эмулятором.
Это использует концепция компиляции Java, а также все интерпретаторы. На любом процессоре, для которого я могу создать интерпретатор / эмулятор, можно запускать мои интерпретируемые программы / байтовый код. В этом заключается основное преимущество интерпретатора над компилятором.
Основы
Начинающий программист представляет себе работу интерпретатора примерно так:
Программист пишет код, запускает его с помощью виртуальной машины, которая его исполняет. Для исполнения кода надо работать с железом — процессором, памятью, жестким диском, сетевой картой и так далее — для таких дел виртуальная машина обращается к операционной системе. Начинающий программист знает, что за счет того, что существуют интерпретаторы под различные операционные системы — код программы оказывается кроссплатформенным.
Чуть более опытный программист исследовал файлы, которые порождает JVM при исполнении программы и знает, что JVM исполняет не исходный код программы, а байт-код, представляющий собой аналог ассемблера для виртуального Java-процессора. Байт-код генерируется загрузчиком классов и помещается в файлы с расширением . Загрузка классов выполняется динамически, то есть когда виртуальная машина, сталкивается с неизвестным ей (не загруженным) классом — она обращается к загрузчику. Очень хорошо информация о байт-коде представлена в статье Java Bytecode Fundamentals .
Интерпретатор C / C++ Ch Embeddable (стандартная версия)
Интерпретатор C / C++, поддерживающий стандарт ISO 1990 C (C90), основные функции C99, классы C++, а также расширения к языку С, такие как вложенные функции, строковый тип и т. д. Он может быть встроен в другие приложения и аппаратные средства, использоваться в качестве языка сценариев. Код C / C++ интерпретируется напрямую без компиляции промежуточного кода. Поскольку этот интерпретатор поддерживает Linux, Windows, MacOS X, Solaris и HP-UX, созданный вами код можно перенести на любую из этих платформ. Стандартная версия бесплатна для личного, академического и коммерческого использования. Для загрузки пакета необходимо зарегистрироваться.
Классификация трансляторов
Транслятор (англ. translator — переводчик) — это программа-переводчик. Она преобразует программу, написанную на одном из языков программирования, в бинарный файл программы, состоящей из машинных команд, либо непосредственно выполняет действия программы.
Трансляторы реализуются в виде компиляторов, интерпретаторов, препроцессоров и эмуляторов. С точки зрения выполнения работы компилятор и интерпретатор существенно различаются.
Компилятор (англ. compiler — составитель, собиратель) — читает всю программу целиком, делает ее перевод и создает законченный вариант программы на машинном языке, то есть бинарный файл, содержащий перечень машинных команд. Бинарный файл может быть исполняемым, библиотечным, объектным), он выполняется.операционной системой без участия компилятора.
Интерпретатор (англ. interpreter — истолкователь, переводчик) — переводит программу построчно (по одному оператору) в машинный код (команды процессора, ОС, иной среды), выполняет переведенный оператор (строку программы), а затем переходит к следующей строке программного текста. Интерпретатор не формирует исполняемых файлов, он сам выполняет все действия, записанные в тексте исходной программы.
После того, как программа откомпилирована, ни сама исходная программа, ни компилятор более не нужны. В то же время программа, обрабатываемая интерпретатором, должна заново переводиться на машинный язык при каждом очередном запуске программы.
Откомпилированные программы работают быстрее, но интерпретируемые проще исправлять и изменять.
Каждый конкретный язык ориентирован либо на компиляцию, либо на интерпретацию — в зависимости от того, для каких целей он создавался. Например, Паскаль обычно используется для решения довольно сложных задач, в которых важна скорость работы программ. Поэтому данный язык обычно реализуется с помощью компилятора.
С другой стороны, Бейсик создавался как язык для начинающих программистов, для которых построчное выполнение программы имеет неоспоримые преимущества.
Иногда для одного языка имеется и компилятор, и интерпретатор. В этом случае для разработки и тестирования программы можно воспользоваться интерпретатором, а затем откомпилировать отлаженную программу, чтобы повысить скорость ее выполнения.
Препроцессор — это транслятор с одного языка программирования в другой без создания исполняемого файла или выполнения программы.
Препроцессоры удобны для расширения возможностей языка и удобства программирования путем использования на этапе написания программы более удобного для человека диалекта языка программирования и ее перевода препроцессором на текст стандартного языка программирования, который можно откомпилировать стандартным компилятором.
Эмулятор — функционирующее в некоторой целевой операционной системе и аппаратной платформе программное и/или аппаратное средство, предназначенное для исполнения программ, изготовленных в другой операционной системе или работающих на отличном от целевого аппаратном обеспечении, но позволяющее осуществлять те же самые операции в целевой среде, что и в имитируемой системе.
К эмулирующим языкам относятся такие системы, как Java, .Net, Mono, в которых на этапе создания программы производится ее компиляция в специальный байт-код и получение бинарного файла, пригодного для исполнения в любой операционной и аппаратной среде,а исполнение полученного байт-кода производится на целевой машине с помощью простого и быстрого интерпретатора (виртуальной машины).
Реассемблер, дизассемблер — программное средство, предназначенное для расшифровки бинарного кода с представлением его в виде текста ассемблера или текста иного языка программирования, позволяющее проанализировать алгоритм исходной программы и использовать полученный текст для необходимой модификации программы, к примеру поменять адреса внешних устройств, обращения к системным и сетевым ресурсам, выявить скрытые функции бинарного кода (к примеру, компьютерного вируса или иной зловредной программы: трояна, червя, кейлоггера и пр.).
Знаете ли Вы, что абстракция через параметризацию — это прием программирования, позволяющий, используя параметры, представить фактически неограниченный набор различных вычислений одной программой, которая есть абстракция этих наборов.
За и против
Основным аргументом за использование процесса компиляции является скорость. Возможность компилировать любой программный код в машинный, который может понять процессор ПК, исключает использование промежуточного кода. Можно запускать программы без дополнительных шагов, тем самым увеличивая скорость обработки кода.
Но наибольшим недостатком компиляции является специфичность. Когда компилируете программу для работы на конкретном процессоре, вы создаете объектный код, который будет работать только на этом процессоре. Если хотите, чтобы программа запускалась на другой машине, вам придется перекомпилировать программу под этот процессор. А перекомпиляция может быть довольно сложной, если процессор имеет ограничения или особенности, не присущие первому. А также может вызывать ошибки компиляции.
Основное преимущество интерпретации — гибкость. Можно не только запускать интерпретируемую программу на любом процессоре или платформе, для которых интерпретатор был скомпилирован. Написанный интерпретатор может предложить дополнительную гибкость. В определенном смысле интерпретаторы проще понять и написать, чем компиляторы.
С помощью интерпретатора проще добавить дополнительные функции, реализовать такие элементы, как сборщики мусора, а не расширять язык.
Другим преимуществом интерпретаторов является то, что их проще переписать или перекомпилировать для новых платформ.
Написание компилятора для процессора требует добавления множества функций, или полной переработки. Но как только компилятор написан, можно скомпилировать кучу интерпретаторов и на выходе мы имеем перспективный язык. Не нужно повторно внедрять интерпретатор на базовом уровне для другого процессора.
Самым большим недостатком интерпретаторов является скорость. Для каждой программы выполняется так много переводов, фильтраций, что это приводит к замедлению работы и мешает выполнению программного кода.
Это проблема для конкретных real-time приложений, таких как игры с высоким разрешением и симуляцией. Некоторые интерпретаторы содержат компоненты, которые называются just-in-time компиляторами (JIT). Они компилируют программу непосредственно перед ее исполнением. Это специальные программы, вынесенные за рамки интерпретатора. Но поскольку процессоры становятся все более мощными, данная проблема становится менее актуальной.
Сравнительная таблица
Основа для сравнения | Компилятор | Переводчик |
---|---|---|
Ввод | Это занимает целую программу за раз. | Это занимает одну строку кода или инструкции за раз. |
Выход | Он генерирует промежуточный объектный код. | Он не создает промежуточного объектного кода. |
Рабочий механизм | Компиляция выполняется перед выполнением. | Компиляция и исполнение происходят одновременно. |
Скорость | Сравнительно быстрее | Помедленнее |
объем памяти | Требование к памяти больше связано с созданием объектного кода. | Он требует меньше памяти, так как не создает промежуточный объектный код. |
Ошибки | Отображать все ошибки после компиляции одновременно. | Отображает ошибку каждой строки по очереди. |
Обнаружение ошибок | Трудно | Сравнительно легче |
Соответствующие языки программирования | C, C ++, C #, Scala, машинописный текст использует компилятор. | PHP, Perl, Python, Ruby используют интерпретатор. |
Работа с памятью
Почти все знают, что языки типа Java/Python очень удобные, т.к. автоматизируют сборку мусора. Это значит, что если вы выделите память под объект (например, массив), а затем этот объект станет вам не нужен — то виртуальная машина сама освободит память. Например, в следующей программе при вызове функции создается новый объект , который после завершения работы функции становится недоступен — это и есть мусор. В языке C++ такие объекты уничтожаются в момент выхода из функции, а в Java, Python и многих других интерпретируемых языках — они живут до тех пор, пока свободная память не кончится:
public class Main { public static void say(String name) { String text = "hello " + name; System.out.println(text); } public static void main(String[] args) { say("Bob"); } }
Опытный программист знает что существуют различные типы сборщиков и запуская программу можно указать какой тип сборщика использовать.
Система управления памятью занимается не только сборкой мусора, но также:
- выделением памяти — так, чтобы избежать фрагментации;
- запросом новых страниц памяти у операционной системы и возвратом освобожденных;
- обнаружением мусора (объектов, которые можно удалить). При этом используется анализ доступности (подсчет ссылок в многопоточной среде не работает).
Вся эта дополнительная работа выполняется неявно в момент выполнения вашей программы и, естественно, тормозит. Обычно для сборки памяти необходима полная остановка вашей программы (всех потоков), поэтому когда память кончится — программа «зависнет» пока не закончит сборку. Память требуется не только для объектов в вашей программе, но и для работы самой JVM, в частности, объектами являются и потребляют память: загруженные классы; код, скомпилированный с помощью JIT; оптимизированный код.
Выше отмечалось, что компиляция и оптимизация могут выполняться многократно во время работы программы, в зависимости от того, как эта программа используется. После оптимизации в памяти оказывается не только оптимизированный код, но и изначальный — на случай если программа начнет использоваться по другому сценарию и потребуется «откат оптимизации». Поэтому модуль оптимизации занимается также «деоптимизацией». Следовательно, от менеджера памяти зависят все элементы интерпретатора и загрузчик.
Как и все остальные темы, работу с памятью в виртуальных машинах мы рассмотрим более подробно в следующих статьях. На текущем этапе должно быть понятно, что:
- помимо вашей программы, виртуальная машина выполняет очень много дополнительной работы;
- виртуальная машина имеет опции запуска, позволяющие управлять этой работой.
Понимая некоторые детали устройства виртуальной машины можно не только обоснованно выбрать опции для нее, но и писать более эффективный код. Это лучше чем заучить наизусть сотни рекомендаций типа:
String bad = new String("Slower"); String good = "Faster";
Дополнительная литература по теме:
- Тюнинг JVM на примере одного проекта. URL: https://habr.com/en/company/luxoft/blog/174231/
- Java Bytecode Fundamentals. URL: https://habr.com/ru/post/111456/
- PGO: уход и кормление. URL: https://vk.com/for_programmer?w=wall-105242702_801
- Как работает JS: о внутреннем устройстве V8 и оптимизации кода. URL: https://habr.com/ru/company/ruvds/blog/337460/
- Martinsen, J. K., Grahn, H. (2010). An alternative optimization technique for JavaScript engines. Presented at the Third Swedish Workshop on Multi-Core Computing (MCC-10), Göteborg: Chalmers University of Technology. Retrieved from http://urn.kb.se/resolve?urn=urn:nbn:se:bth-7688
- Введение в технологии виртуализации.
Классификация разных типов компиляторов
- Собственный компилятор
- Компилятор, который сам генерирует целевой код для платформы, на которой он работает. Код зависит от платформы.
- Кросс-компилятор
→ Основная статья : Кросс-компилятор
- Компилятор, который работает на одной платформе и генерирует целевой код для другой платформы, например для другой операционной системы или другой архитектуры процессора .
- Типичное приложение — это создание программ для встроенной системы, которая сама по себе не содержит никаких инструментов или хороших инструментов для создания программного обеспечения, а также создание или перенос операционной системы на новую платформу.
- Компилятор за один проход
- Компилятор, который генерирует целевой код из исходного кода за один проход (в отличие от многопроходного компилятора); компилятор читает исходный текст от начала до конца только один раз и одновременно генерирует программу результата. Такой компилятор обычно очень быстр, но может выполнять только простые оптимизации. Однопроходный компилятор может быть создан только для определенных языков программирования, например Pascal , C и C ++ , потому что язык программирования не должен содержать никаких прямых ссылок (нельзя использовать ничего, что еще не было объявлено «выше» в исходный код).
- Многопроходный компилятор
- В этом типе компилятора исходный код транслируется в целевой код в несколько этапов (изначально: исходный код читается несколько раз или прорабатывается несколько раз «от начала до конца»). На заре создания компилятора процесс трансляции в основном делился на несколько прогонов, потому что у компьютера часто не хватало мощности для одновременного размещения в основной памяти полного компилятора и транслируемой программы. В настоящее время многопроходный компилятор в основном используется для разрешения прямых ссылок ( объявление идентификатора «ниже в исходном коде» в качестве его первого использования) и для выполнения сложных оптимизаций.
Заключение
Всегда июмейте всегда в виду, что некоторые языки программирования специально предназначены для компиляции кода, например, C. В то время как другие языки всегда должны интерпретироваться, например Java.
Для меня не имеет значения, скомпилировано что-то или интерпретировано, если оно может выполнить задачу эффективно.
Некоторые системы не предлагают технические условия для эффективного использования интерпретаторов. Поэтому вы должны запрограммировать их с помощью чего-то, что может быть непосредственно скомпилировано, например C. Иногда нужно выполнить вычисления настолько интенсивно, насколько это возможно. Например, при точном распознавании голоса роботом. В других случаях скорость или вычислительная мощность могут быть не столь критичными, и написать эмулятор на оригинальном языке может быть проще.
Сообщите мне, что бы вы предпочли: интерпретацию или компиляцию? Спасибо за уделенное время!
Вывод
И компилятор, и интерпретатор предназначены для выполнения одной и той же работы, но различаются по рабочей процедуре. Компилятор принимает исходный код агрегированным образом, тогда как интерпретатор принимает составные части исходного кода, то есть оператор за оператором.
Хотя и компилятор, и интерпретатор имеют определенные преимущества и недостатки, например, интерпретируемые языки считаются кроссплатформенными, то есть код переносимый. В отличие от компилятора, ему также не нужно предварительно компилировать инструкции, что позволяет сэкономить время. Скомпилированные языки быстрее в процессе компиляции.