Будьте осторожны с тем, о каком виде использования памяти вы говорите.
Код, скомпилированный для 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-компилятора является одним из факторов, но это не всегда важно.