Динамическая и инкрементная компиляция: принципы и особенности
Dynamic compilation
Динамическая компиляция: повышение производительности программ во время выполнения. Java – яркий пример. Оптимизация в реальном времени, но с начальной задержкой.
Сравнивайте с английским: нажмите на абзац — оригинал откроется в окне. Кнопка EN под абзацем показывает его прямо в тексте.
Введение
Динамическая компиляция — это процесс, используемый некоторыми реализациями языков программирования для повышения производительности во время выполнения программы. Хотя эта техника возникла в Smalltalk, наиболее известным языком, использующим её, является Java. Поскольку машинный код, генерируемый динамическим компилятором, создаётся и оптимизируется во время выполнения программы, использование динамической компиляции позволяет проводить оптимизации для повышения эффективности, недоступные статически компилируемым программам (то есть программам, компилируемым так называемым "пакетным компилятором", как указано ниже), за исключением дублирования кода или метапрограммирования. Среды выполнения, использующие динамическую компиляцию, обычно демонстрируют медленную работу программ в течение первых нескольких минут, после чего большая часть компиляции и перекомпиляции завершается, и программа начинает работать быстро. Из-за этой первоначальной задержки производительности динамическая компиляция нежелательна в определённых случаях. В большинстве реализаций динамической компиляции некоторые оптимизации, которые могли бы быть выполнены на начальном этапе компиляции, откладываются до последующей компиляции во время выполнения, что приводит к дальнейшим ненужным замедлениям. Компиляция Just-in-Time является формой динамической компиляции.
Dynamic compilation is a process used by some programming language implementations to gain performance during program execution. Although the technique originated in Smalltalk, the best known language that uses this technique is Java. Since the machine code emitted by a dynamic compiler is constructed and optimized at program runtime, the use of dynamic compilation enables optimizations for efficiency not available to statically compiled programs (i. e. those compiled by a so called "batch compiler", as written below) except through code duplication or metaprogramming. Runtime environments using dynamic compilation typically have programs run slowly for the first few minutes, and then after that, most of the compilation and recompilation is done and it runs quickly. Due to this initial performance lag, dynamic compilation is undesirable in certain cases. In most implementations of dynamic compilation, some optimizations that could be done at the initial compile time are delayed until further compilation at run time, causing further unnecessary slowdowns. Just in time compilation is a form of dynamic compilation.
Инкрементальная компиляция
Тесно связанной техникой является инкрементная компиляция. Инкрементный компилятор используется в POP 2, POP 11, Forth, некоторых версиях Lisp, например, Maclisp и как минимум в одной версии ML (Poplog ML). Это требует, чтобы компилятор языка программирования был частью среды выполнения. В результате исходный код можно загружать в любое время – из терминала, из файла или, возможно, из структуры данных, созданной работающей программой – и преобразовывать в блок машинного кода или функцию (которая может заменить предыдущую функцию с тем же именем), которая затем немедленно становится доступной для использования программой. Из-за необходимости высокой скорости компиляции в процессе интерактивной разработки и тестирования, скомпилированный код, скорее всего, не будет оптимизирован так тщательно, как код, созданный стандартным "пакетным компилятором", который считывает исходный код и генерирует объектные файлы, которые впоследствии можно связать и запустить. Однако программа, скомпилированная инкрементно, обычно работает значительно быстрее, чем интерпретируемая версия той же программы. Таким образом, инкрементная компиляция сочетает в себе преимущества интерпретируемых и компилируемых языков. Для повышения переносимости обычно желательно, чтобы инкрементный компилятор работал в два этапа: сначала компилируя в промежуточный платформенно-независимый язык, а затем – из него в машинный код для целевой машины. В этом случае для переноса достаточно изменить только "бэкэнд" компилятор. В отличие от динамической компиляции, как определено выше, инкрементная компиляция не предполагает дальнейшей оптимизации после первого запуска программы.
A closely related technique is incremental compilation. An incremental compiler is used in POP 2, POP 11, Forth, some versions of Lisp, e. g. Maclisp and at least one version of ML (Poplog ML). This requires the compiler for the programming language to be part of the runtime system. In consequence, source code can be read in at any time, from the terminal, from a file, or possibly from a data structure constructed by the running program, and translated into a machine code block or function (which may replace a previous function of the same name), which is then immediately available for use by the program. Because of the need for speed of compilation during interactive development and testing, the compiled code is likely not to be as heavily optimised as code produced by a standard 'batch compiler', which reads in source code and produces object files that can subsequently be linked and run. However an incrementally compiled program will typically run much faster than an interpreted version of the same program. Incremental compilation thus provides a mixture of the benefits of interpreted and compiled languages. To aid portability it is generally desirable for the incremental compiler to operate in two stages, namely first compiling to some intermediate platform independent language, and then compiling from that to machine code for the host machine. In this case porting requires only changing the 'back end' compiler. Unlike dynamic compilation, as defined above, incremental compilation does not involve further optimisations after the program is first run.