Почему код JIT'Ed потребляет намного больше памяти, чем скомпилированный или интерпретированный код?

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

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

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

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

2 ответов


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

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

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

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


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

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

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

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

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

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

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

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

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


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