使用ctypes在共享库中释放calloc

时间:2014-12-29 07:57:04

标签: python c memory-management ctypes calloc

我有这个结构:

struct result {
    int position;
    int *taken;
};

struct result get_result(int pos, int take[]){
    struct result res;
    res.position = pos;
    res.taken = take;
    return res;
}

我在函数中调用它:

struct result get_taken_values(){
    //some code
    int position = 0;
    int* chosen = calloc(9, sizeof(int));     
    //some more code
    struct result res;
    res.position = position;
    res.taken = chosen;
    return res;
}

如果我在main中使用它,我只需拨打free(res.taken) in the end

但是我使用以下方法将其转换为共享库:

gcc -fPIC -c get_taken_values.c
ld -shared -soname libtest.so.1 -o my_library.so -lc get_taken_values.o

我将使用ctypes在Python中使用此库。

我是否需要释放calloc,如果是,我该怎么做?

1 个答案:

答案 0 :(得分:1)

假设您需要taken的可变大小数组,那么您可以创建一个ctypes.Structure,为其提供一个__del__方法,该方法将调用free。您可以通过加载free来致电libc。在对象的最后一次引用超出范围之后调用__del__。如果你的对象包含循环引用,使用__del__可能会导致问题,因为python不会首先知道要调用__del__的对象(所以它不会,它只是让对象在内存中保持不变)

from ctypes import Structure, c_int, POINTER, CDLL
from ctypes.util import find_library

__all__ = ["get_taken_values", "Result"]

libc = CDLL(find_library("c"))
libmy_library = CDLL("./my_library.so")

class Result(Structure):
    _fields_ = [
        ("position", c_int),
        ("taken", POINTER(c_int)),
        ("size", c_int)
    ]

    def __str__(self):
        return "result(position={}, taken={})".format(
            self.position, self.taken[:self.size])

    def __del__(self):
        libc.free(self.taken)

get_taken_values = libmy_library.get_taken_values
get_taken_values.argtypes = ()
get_taken_values.restype = Result

if __name__ == "__main__":
    result = get_taken_values()
    print("position is {} and value at position is {}".format(
        result.position, result.taken[result.position]))
    print(result)

这假设python Result的实例是内存的所有者。此外,如果taken确实是可变大小的,那么您需要在Result引用的结构中包含size成员。如果taken是固定大小,那么您可以在结构中声明为数组,忘记使用free,并在声明{{1}类型时使用c_int * 9而不是POINTER(c_int)在python中。