我正在尝试创建一个继承自int或cython.int的扩展类型。这对我来说是必要的,因为我需要能够将此类型用作某些列表/数组的索引。
以下是在Anaconda上使用Cython v0.22重现Python 2.7.9 Win32(我运行Windows 7)上的错误的代码:
import cython
cimport cython
import sys
cdef class ExtendedInt(int):
#cdef object __weakref__ # explicitly enable weakref for this extension type, will self-destruct when it is no longer strongly referenced.
def __add__(a, b):
return a+b
# Simple test case
def main():
total_it = 1000
for i in xrange(total_it):
for j in xrange(10000000):
ExtendedInt(j)
sys.stdout.write("\rGenerating lists of ExtendedInt : %i/%i" % (i, total_it))
如果你试图创建大量的ExtendedInt,那么Python解释器会在某个时刻崩溃并出现MemoryError。使用上面的代码片段,在我的具有4 GB内存的计算机上,它会在第11次迭代时崩溃,但这将根据计算机规格而有所不同。我尝试启用weakref,但它没有解决问题。
但是,如果你替换" cdef类ExtendedInt(int):"只需"类ExtendedInt(int)" (所以它不再是扩展类型,而是一个简单的Python类),那么问题就不会发生,没有MemoryError崩溃。
因此,即使我启用了 weakref ,似乎也没有正确释放从整数继承的扩展类型。这是我应该填写跟踪器的错误还是我错过了什么?
这是当前Cython版本的错误吗?我找不到关于bugtracker的任何参考......或者我错过了可以解决这个问题的东西?
答案 0 :(得分:0)
Stefan Behnel discovered that the bug is in Python 2.7 inside intobject.c:
您的扩展类型会自动继承“int_free”插槽 函数来自其基类型,因此“int_dealloc()”中的“else”情况 实际上会调用“int_free()”并将该对象追加到空闲列表中 尽管不完全属于PyInt类型。然后,在创建新的时 ExtendedInt实例,Python的int-subtype实例化代码 忽略自由列表,而是创建一个全新的对象。
因此,自由列表不断增长,直到它填满所有内存和 过程死亡。我创建了一张CPython票。
以下是Guido Van Rossum的答案:
预期的解决方案是要求int子类重写 tp_free。
请注意,大部分代码都是在假设的情况下编写的 子类是使用类语句创建的(在常规Python中 模块,而不是Cython)负责所有这些细节。事实并非如此 意味着Cython尝试这个是错误的,但它确实意味着没有太多 文档,这也意味着我不认为你的事情 据报道,它被认为是CPython中的一个错误。
所以我不确定这是否会得到解决或者Cython是否会实施解决方法。无论如何,对于那些面临同样问题的人,你可以通过继承object来解决这个问题,然后重新实现整数的魔术方法,比如 int , index ,正如我在a concrete example here中解释的那样添加等。