Python: ctypes和垃圾回收

3

我有以下代码片段,它展示了动态分配的矩阵(二维数组)

C语言

int** create_matrix(int r, int c)
{
    int i, j, count;

    int **arr = (int **)malloc(r * sizeof(int *));
    for (i=0; i<r; i++)
        arr[i] = (int *)malloc(c * sizeof(int));


    count = 0;
    for (i = 0; i <  r; i++)
       for (j = 0; j < c; j++)
          arr[i][j] = ++count;  

    return arr;
}

Python (调用C函数)

r = 3
c = 3
p_int = POINTER(POINTER(c_int))
testlib.create_matrix.restype = POINTER(POINTER(c_int))
p_int = testlib.create_matrix(r, c) #does p_int and inner array deallocated automatically in python?

我的问题是:

  1. Python/ctypes是否处理由C分配的内存的释放?
  2. 如果我们需要手动释放它,应该如何操作?调用free还是其他什么?
    • 任何澄清此问题的博客或文章都非常好。

你为什么要添加 p_int = POINTER(POINTER(c_int)) 这一行代码呢?它并没有起到任何实际作用。 - Eryk Sun
ctypes不会释放指针数组,也不会释放行。首先,它不拥有内存,所以那将是一个可怕的想法。此外,它不知道p_int指向指针数组,也不知道数组的长度,那么它怎么知道需要调用free r+1次呢? - Eryk Sun
1个回答

2
Python/ctypes是否处理由C分配的内存的释放?
如果您的代码调用了malloc();则您有责任调用调用free()的代码。
如果我们要求手动释放它,那么如何? 调用free还是其他什么东西?任何澄清此事的博客或帖子都将非常好。
C代码应提供互补的free_matrix()函数,该函数应由调用create_matrix()的代码调用。 有很多free_matrix()的实现,例如{{link1:example}}。
您可以将create_matrix(),free_matrix()包装到一个对象中,并在其__del__()方法中调用free_matrix()。 如果您想要更确定性的方法(__del__()被调用的时间或是否被调用取决于实现的方式),则可以创建上下文管理器:
from contextlib import contexmanager

@contextmanager
def matrix():
    m = Matrix() # calls create_matrix() internally
    try:
        yield m # Matrix() may protect against out-of-bound error
    finally:
        m.clear() # call free_matrix()

例子:

with matrix() as m:
   print(m[0][1])

1
+1,但如果可能的话,库应该允许客户端分配聚合数据。在这种情况下,操作员可以使用类似于 p_int = (c_int * c * r)() 的 ctypes 数组,由解释器进行引用计数。 - Eryk Sun
@eryksun:是的。接受预分配的缓冲区是一个好选择。请注意:为了清晰起见,避免与(c_int * (c * r))混淆,请使用((c_int * c) * r) - jfs
通常我会避免使用括号来澄清运算顺序和二元操作,除非是一个特别复杂的表达式。我认为 c_int * c * r 的计算是不言自明的。 - Eryk Sun
1
@eryksun:鉴于在大多数情况下 * 是一个具有结合性的运算符,与此不同的是,在这种情况下,即使您自己总是记得正确的解释,也有必要使用括号。 - jfs

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