为什么Psyco会使用大量内存?

5

Psyco 是一种专为 Python 设计的编译器。根据文档所述:

Psyco 可以并且会使用大量内存。

这种内存使用的主要原因是什么?在 JIT 编译器中,是否普遍存在大量内存开销?

编辑:感谢目前为止提供的答案。有三个可能的原因:

  • 编写多个专门的代码块,每个代码块都需要内存
  • 即时编译源代码导致的开销
  • 捕获足够的数据以进行动态分析导致的开销

问题是,哪一个是内存使用的主要因素?我有自己的看法。但我添加了一个赏金,因为我想接受实际正确的答案!如果有人能证明或证明大部分内存用于何处,我会接受它。否则,在赏金结束时,由社区投票选出的将被自动接受。

4个回答

10
从Psyco网站上可以看到:“与传统的JIT编译器方法不同的是,Psyco编写了同一块代码的多个版本(一个块是函数的一部分),这些版本通过对某些类型的变量进行特化来进行优化(“类型”可以是指数据类型,但更为通用)。”

5
"Psyco使用程序实际操作的运行时数据编写可能有多个版本的机器码,每个版本都针对不同类型的数据进行了不同的专门优化。" http://psyco.sourceforge.net/introduction.html
许多JIT编译器适用于静态类型语言,因此它们知道类型是什么,可以为已知类型创建机器码。更好的编译器会在遇到多态类型时进行动态分析,并优化常见的路径;这通常也用于具有动态类型的语言。Psyco似乎采取保守策略,以避免进行完整的程序分析来决定可能的类型,或者进行分析以找出正在使用的类型。
†我从未深入研究Python是否具有动态类型(在创建具有该类型的对象后可以在运行时更改其结构的类型),或者只是常见实现仅在运行时检查类型;大多数文章只是狂热地谈论动态类型,而没有在Python环境中定义它。

4
好的,我会尽力进行翻译:“很好地运用了 &dagger 实现了一个看起来正规的脚注!” - unwind
你绝对可以在实例化类的过程中动态地添加成员和函数。你也可以卸载、修改包含类的模块,然后重新加载并开始使用新的类。 - Jon Cage
这会改变那个类的现有对象吗,还是只会影响重新加载后创建的新对象? - Pete Kirkham
如果您更改类,已创建的对象仍将存在于原始类中。您也可以直接修改对象以使其与原始类不同。 - Esteban Küber

2
Psyco的内存开销目前较大。随着时间的推移,它有所减少,但仍是一种开销。这种开销与Psyco重写的Python代码量成比例;因此,如果您的应用程序具有一些算法“核心”函数,那么这些函数就是您想要Psyco加速的函数,而不是整个程序。
因此,我认为需要大量内存的原因是它将源代码加载到内存中,然后在运行时编译它。您尝试编译的源代码越多,它需要的内存就越多。我猜想,如果它还要进行优化,它将查看多个可能的解决方案,以确定最佳情况。

2

Psyco内存的使用主要来自于编译后的汇编代码块。有时候,Psyco会受到函数过度特化的影响,这意味着可能存在多个汇编代码块的版本。此外,非常重要的一点是,即使与其相关联的代码已经死亡,Psyco也从不释放已经分配的汇编代码块。

如果您在Linux下运行程序,可以查看/proc/xxx/smaps以查看一个匿名内存块的不断增长,该内存块位于堆之外的不同区域。那是为了记录汇编代码而匿名mmap出来的部分,当然在没有Psyco的情况下运行时会消失。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接