7

编译后的代码如C占用很少的内存。

解释代码之类的Python会消耗更多的内存,这是可以理解的。

使用 JIT,程序在运行时(有选择地)编译成机器代码。那么,JIT 程序的内存消耗不应该介于编译程序和解释程序之间吗?

相反,经过 JIT 处理的程序(例如PyPy)消耗的内存是等效的解释程序(例如 )的几倍Python。为什么?

4

2 回答 2

8

跟踪 JIT 编译器会占用更多内存,因为它们不仅需要保留 VM 的字节码,还需要保留直接可执行的机器代码。然而,这只是故事的一半。

大多数 JIT 还将保留大量有关字节码(甚至机器码)的元数据,以允许他们确定需要 JIT 的内容以及可以保留的内容。跟踪 JIT(例如 LuaJIT)还创建跟踪快照,用于在运行时微调代码,执行循环展开或分支重新排序等操作。

有些还保留常用代码段的缓存或快速查找缓冲区以加速 JIT 代码的创建(LuaJIT 通过 DynAsm 执行此操作,如果正确完成,它实际上可以帮助减少内存使用,就像 dynasm 的情况一样)。

内存使用很大程度上取决于所使用的 JIT 引擎及其编译的语言的性质(强类型与弱类型)。一些 JIT 采用了先进的技术,例如基于 SSA 的寄存器分配器和变量活跃度分析,这些优化也有助于消耗内存,以及循环变量提升等更常见的事情。

于 2011-12-30T02:22:38.710 回答
5

请注意您所说的内存使用情况

编译为 C 的代码对编译的机器代码本身使用的内存相对较少。

我希望给定算法的 Python 字节码实际上小于类似算法的编译 C 代码,因为 Python 字节码操作的级别要高得多,因此完成给定任务的操作通常更少。但是一个 Python 程序也会在内存中拥有 Python 解释器的编译代码,这本身就是一个相当庞大和复杂的程序。另外,一个典型的 Python 程序将比典型的 C 程序在内存中拥有更多的标准库(如果 C 程序是静态链接的,它可以去掉它实际上不使用的所有函数,如果它是动态链接的,那么它共享编译后的代码与内存中使用它的任何其他进程)。

然后,PyPy 拥有 JIT 编译器的机器代码,以及从 Python 字节码生成的机器代码(它不会消失,它也必须保留)。因此,您的直觉(即 JITed 系统“应该”消耗介于编译语言和完全解释语言之间的内存)无论如何都不正确。

但除此之外,您还拥有程序运行的数据结构所使用的实际内存。这变化很大,与程序是提前编译、解释还是解释和 JIT 无关。一些编译器优化会减少内存使用(无论是提前应用还是及时应用),但许多实际上会权衡内存使用以提高速度。无论如何,对于处理任何大量数据的程序,它将完全使代码本身使用的内存相形见绌。

当你说:

相反,经过 JIT 处理的程序(例如 PyPy)消耗的内存是等效的解释程序(例如 Python)的数倍。为什么?

你在想什么节目?如果您实际上已经进行了任何比较,那么我从您的问题中猜测它们将介于 PyPy 和 CPython 之间。我知道 PyPy 的许多数据结构实际上比 CPython 的小,但同样,这与 JIT 无关。

如果程序的主要内存使用是代码本身,那么 JIT 编译器会增加巨大的内存开销(对于编译器本身和已编译的代码),并且根本无法通过以下方式“赢回”内存使用优化。如果主要的内存使用是程序数据结构,那么无论是否启用了 JIT,我都会发现 PyPy 使用的内存比 CPython 少得多。


您的“为什么?”并没有一个直接的答案。因为您问题中的陈述并非完全正确。哪个系统使用更多内存取决于许多因素;JIT 编译器的存在与否是一个因素,但它并不总是很重要。

于 2011-12-30T03:27:40.000 回答