Cython memoryview error - Fatal Python error: Acquisition count is
Cython memoryview error - Fatal Python error: Acquisition count is
我在使用 Cython 时遇到了一个我发现很难解决的错误。
我有一个结构 ret_val,它有一个名为 last_visited 的 long[:] 字段。
我正在尝试设置它但出现以下运行时错误:
Fatal Python error: Acquisition count is -1753032536 (line 5052)
以下是上面一行负责的 C 文件的摘录:
/* "cymain.pyx":196
* last = np.array([1,1,1], dtype=np.int64)
* ret_val.last_visited = last # <<<<<<<<<<<<<<
*/
__pyx_t_9 = __Pyx_PyObject_to_MemoryviewSlice_ds_long(__pyx_v_last);
if (unlikely(!__pyx_t_9.memview)) {
__pyx_filename = __pyx_f[0];
__pyx_lineno = 196;
__pyx_clineno = __LINE__;
goto __pyx_L1_error;
}
__PYX_XDEC_MEMVIEW(&__pyx_v_ret_val->last_visited, 0);
__pyx_v_ret_val->last_visited = __pyx_t_9;
__pyx_t_9.memview = NULL;
__pyx_t_9.data = NULL;
我试着做了一个最小的例子来重现错误,但后来并没有发生。然后我用最小的例子重写了这个函数,又失败了。
这是一个不会产生错误的最小示例,但据我所知,它在功能上与导致错误的代码相同:
cdef struct baz:
long[:] lv
othermodule.something* cd
cdef baz* initialise_baz(dict req):
cdef:
baz* ret_val = <baz *> malloc(sizeof(baz))
long nlevels = 3
ret_val.cd = NULL
lv = req["key"]
lv = np.array(lv, dtype=np.int64)
ret_val.lv = lv
return ret_val
def test_memview_error(req):
cdef baz* foo
foo = initialise_baz(req)
print "foo.lv[2]", foo.lv[2]
然后调用
import cymodule
cymodule.test_memview_error({"key":np.array([1,2,3])})
我认为问题与未初始化的内存有关(正如我在评论中所说)。从您的简单示例中查看生成的 C 代码:
/* "code.pyx":5
* import numpy as np
*
* cdef struct baz: # <<<<<<<<<<<<<<
* long[:] lv
* #othermodule.something* cd
*/
struct __pyx_t_4code_baz {
__Pyx_memviewslice lv;
};
(请注意,为简单起见,我已注释掉 othermodule.something
)。 __Pyx_memviewslice
定义为
typedef struct {
struct __pyx_memoryview_obj *memview;
char *data;
Py_ssize_t shape[8];
Py_ssize_t strides[8];
Py_ssize_t suboffsets[8];
} __Pyx_memviewslice;
来自 initialise_baz
的一些相关代码(我在这里跳过了一些小部分)
__pyx_v_ret_val = ((struct __pyx_t_4code_baz *)malloc((sizeof(struct __pyx_t_4code_baz))));
请注意 malloc
不会(必然)将内存归零。因此 lv
的内容(至关重要的是指向 memview
的指针)被设置为任意值(可能是之前内存中的内容 - 这显然取决于您之前的其他代码 运行 ) .如果您使用 calloc
而不是 malloc
它会将内存归零。 initialise_baz
继续:
/* "code.pyx":18
* lv = req["key"]
* lv = np.array(lv, dtype=np.int64)
* ret_val.lv = lv # <<<<<<<<<<<<<<
*
* return ret_val
*/
__pyx_t_6 = __Pyx_PyObject_to_MemoryviewSlice_ds_long(__pyx_v_lv);
if (unlikely(!__pyx_t_6.memview)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 18; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__PYX_XDEC_MEMVIEW(&__pyx_v_ret_val->lv, 0);
__pyx_v_ret_val->lv = __pyx_t_6;
__pyx_t_6.memview = NULL;
__pyx_t_6.data = NULL;
关键行是 __PYX_XDEC_MEMVIEW
在 lv
的先前(任意!)内容上调用。这就是问题所在。 lv.memview
指向任意位置,它从中读取它认为是 acquisition_count
.
的内容
表面的修复是使用 calloc
而不是 malloc
。但是,即使在那种情况下,当您释放 baz
时,lv
也永远不会被正确释放,这可能会导致内存泄漏。我 真的 认为将内存视图用作 C 结构的一部分没有意义。您能否将它们用作 cdef class
的一部分,这样一切都得到妥善处理?
我在使用 Cython 时遇到了一个我发现很难解决的错误。 我有一个结构 ret_val,它有一个名为 last_visited 的 long[:] 字段。 我正在尝试设置它但出现以下运行时错误:
Fatal Python error: Acquisition count is -1753032536 (line 5052)
以下是上面一行负责的 C 文件的摘录:
/* "cymain.pyx":196
* last = np.array([1,1,1], dtype=np.int64)
* ret_val.last_visited = last # <<<<<<<<<<<<<<
*/
__pyx_t_9 = __Pyx_PyObject_to_MemoryviewSlice_ds_long(__pyx_v_last);
if (unlikely(!__pyx_t_9.memview)) {
__pyx_filename = __pyx_f[0];
__pyx_lineno = 196;
__pyx_clineno = __LINE__;
goto __pyx_L1_error;
}
__PYX_XDEC_MEMVIEW(&__pyx_v_ret_val->last_visited, 0);
__pyx_v_ret_val->last_visited = __pyx_t_9;
__pyx_t_9.memview = NULL;
__pyx_t_9.data = NULL;
我试着做了一个最小的例子来重现错误,但后来并没有发生。然后我用最小的例子重写了这个函数,又失败了。
这是一个不会产生错误的最小示例,但据我所知,它在功能上与导致错误的代码相同:
cdef struct baz:
long[:] lv
othermodule.something* cd
cdef baz* initialise_baz(dict req):
cdef:
baz* ret_val = <baz *> malloc(sizeof(baz))
long nlevels = 3
ret_val.cd = NULL
lv = req["key"]
lv = np.array(lv, dtype=np.int64)
ret_val.lv = lv
return ret_val
def test_memview_error(req):
cdef baz* foo
foo = initialise_baz(req)
print "foo.lv[2]", foo.lv[2]
然后调用
import cymodule
cymodule.test_memview_error({"key":np.array([1,2,3])})
我认为问题与未初始化的内存有关(正如我在评论中所说)。从您的简单示例中查看生成的 C 代码:
/* "code.pyx":5
* import numpy as np
*
* cdef struct baz: # <<<<<<<<<<<<<<
* long[:] lv
* #othermodule.something* cd
*/
struct __pyx_t_4code_baz {
__Pyx_memviewslice lv;
};
(请注意,为简单起见,我已注释掉 othermodule.something
)。 __Pyx_memviewslice
定义为
typedef struct {
struct __pyx_memoryview_obj *memview;
char *data;
Py_ssize_t shape[8];
Py_ssize_t strides[8];
Py_ssize_t suboffsets[8];
} __Pyx_memviewslice;
来自 initialise_baz
的一些相关代码(我在这里跳过了一些小部分)
__pyx_v_ret_val = ((struct __pyx_t_4code_baz *)malloc((sizeof(struct __pyx_t_4code_baz))));
请注意 malloc
不会(必然)将内存归零。因此 lv
的内容(至关重要的是指向 memview
的指针)被设置为任意值(可能是之前内存中的内容 - 这显然取决于您之前的其他代码 运行 ) .如果您使用 calloc
而不是 malloc
它会将内存归零。 initialise_baz
继续:
/* "code.pyx":18
* lv = req["key"]
* lv = np.array(lv, dtype=np.int64)
* ret_val.lv = lv # <<<<<<<<<<<<<<
*
* return ret_val
*/
__pyx_t_6 = __Pyx_PyObject_to_MemoryviewSlice_ds_long(__pyx_v_lv);
if (unlikely(!__pyx_t_6.memview)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 18; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__PYX_XDEC_MEMVIEW(&__pyx_v_ret_val->lv, 0);
__pyx_v_ret_val->lv = __pyx_t_6;
__pyx_t_6.memview = NULL;
__pyx_t_6.data = NULL;
关键行是 __PYX_XDEC_MEMVIEW
在 lv
的先前(任意!)内容上调用。这就是问题所在。 lv.memview
指向任意位置,它从中读取它认为是 acquisition_count
.
表面的修复是使用 calloc
而不是 malloc
。但是,即使在那种情况下,当您释放 baz
时,lv
也永远不会被正确释放,这可能会导致内存泄漏。我 真的 认为将内存视图用作 C 结构的一部分没有意义。您能否将它们用作 cdef class
的一部分,这样一切都得到妥善处理?