Почему код JIT потребляет намного больше памяти, чем скомпилированный или интерпретированный код? - PullRequest
7 голосов
/ 30 декабря 2011

Скомпилированный код, такой как C, потребляет мало памяти.

Интерпретированный код, такой как Python, потребляет больше памяти, что понятно.

При использовании JIT программа (выборочно)скомпилирован в машинный код во время выполнения.Так не должно ли потребление памяти JIT-программой находиться где-то между скомпилированной и интерпретируемой программой?

Вместо этого JIT-программа (такая как PyPy) потребляет в несколько раз больше памяти, чем эквивалентная интерпретируемая программа (такая как Python).Почему?

Ответы [ 2 ]

8 голосов
/ 30 декабря 2011

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

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

Некоторые также хранят кэши обычно используемых сегментов кода или буферы быстрого поиска, чтобы ускорить создание кода JIT (LuaJIT делает это через DynAsm, это может реально помочь уменьшить использование памяти при правильном выполнении, как в случае с dynasm) ,

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

5 голосов
/ 30 декабря 2011

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

Код, скомпилированный для C, использует сравнительно мало памяти для самого скомпилированного машинного кода .

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

Затем PyPy имеет машинный код JIT-компилятора, а также машинный код, сгенерированный из байт-кода Python (который не исчезает, его также нужно хранить). Таким образом, ваша интуиция (что система JIT «должна» потреблять память где-то между памятью скомпилированного и полностью интерпретированного языка) в любом случае неверна.

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

Когда вы говорите:

Вместо этого JIT-программа (такая как PyPy) потребляет в несколько раз больше памяти, чем эквивалентная интерпретируемая программа (например, Python). Почему?

О каких программах вы думаете? Если вы действительно проводили какие-либо сравнения, я думаю, что из вашего вопроса они будут между PyPy и CPython. Я знаю, что многие структуры данных PyPy на самом деле меньше, чем структуры CPython, но, опять же, это не имеет ничего общего с JIT.

Если основным использованием памяти программы является сам код, то JIT-компилятор добавляет огромные накладные расходы памяти (как для самого компилятора, так и для скомпилированного кода) и вообще не может сделать очень много, чтобы «отыграться» использование памяти через оптимизацию. Если доминирующим использованием памяти являются программные структуры данных, я бы не удивился, обнаружив, что PyPy использует значительно меньше памяти, чем CPython, независимо от того, был ли включен JIT.


На самом деле нет простого ответа на ваше "Почему?" потому что утверждения в вашем вопросе не совсем верны. Какая система использует больше памяти, зависит от многих факторов; Наличие или отсутствие JIT-компилятора является одним из факторов, но это не всегда важно.

...