使用ctypes时释放内存

时间:2019-01-30 14:19:10

标签: python c numpy ctypes

我正在使用ctypes尝试加快我的代码的速度。

我的问题类似于本教程中的问题:https://cvstuff.wordpress.com/2014/11/27/wraping-c-code-with-python-ctypes-memory-and-pointers/

正如本教程中指出的那样,在使用C函数后,我应该释放内存。这是我的C代码

//C functions
double* getStuff(double *R_list, int items){

    double results[items];  
    double* results_p;   

    for(int i = 0; i < items; i++){ 
            res = calculation ; \\do some calculation
            results[i] = res;   }

        results_p = results;
        printf("C allocated address %p \n", results_p);

return results_p; }

void free_mem(double *a){
    printf("freeing address: %p\n", a);

    free(a);    }

我使用gcc -shared -Wl,-lgsl,-soname, simps -o libsimps.so -fPIC simps.c进行编译

和python:

//Python
from ctypes import *
import numpy as np


mydll = CDLL("libsimps.so")
mydll.getStuff.restype = POINTER(c_double)
mydll.getStuff.argtypes = [POINTER(c_double),c_int]
mydll.free_mem.restype = None
mydll.free_mem.argtypes = [POINTER(c_double)]

R = np.logspace(np.log10(0.011),1, 100, dtype = float) #input


tracers = c_int(len(R))

R_c = R.ctypes.data_as(POINTER(c_double))


for_list = mydll.getStuff(R_c,tracers)
print 'Python allocated', hex(for_list)
for_list_py = np.array(np.fromiter(for_list, dtype=np.float64, count=len(R)))
mydll.free_mem(for_list)

到最后一行,代码执行了我想要的操作,并且for_list_py值正确。但是,当我尝试释放内存时,出现分段错误,并且在仔细检查后,与for_list-> hex(for_list)关联的地址与分配给{{1}的地址不同}放在代码的C部分中。

如该问题所指出的,如果results_p设置为for_list,则Python ctypes: how to free memory? Getting invalid pointer errormydll.getStuff.restype将返回相同的地址。但是后来我努力将我想要的实际值放入c_void_p中。这是我尝试过的:     演员(for_list,POINTER(c_double))     for_list_py = np.array(np.fromiter(for_list,dtype = np.float64,count = len(R)))     mydll.free_mem(for_list) 其中的强制转换操作似乎将for_list更改为整数。我对C还是很陌生,非常困惑。我需要释放那块内存吗?如果是这样,我该怎么做,同时又将输出保存在numpy数组中?谢谢!

编辑:看来,在C中分配的地址和我要释放的地址是相同的,尽管我仍然收到分段错误。

for_list_py

如果我C allocated address 0x7ffe559a3960 freeing address: 0x7ffe559a3960 Segmentation fault 会得到print for_list

结论

只是让大家知道,我在使用c_types时有些挣扎。

我最终选择了SWIG而不是c_types。我发现代码总体上运行得更快(与此处提供的版本相比)。我发现这份关于处理SWIG中的内存释放的文档非常有用https://scipy-cookbook.readthedocs.io/items/SWIG_Memory_Deallocation.html,而且SWIG为您提供了一种非常简单的方式处理numpy n维数组的方法。

1 个答案:

答案 0 :(得分:1)

退出getStuff函数后,分配给results数组的内存不再可用,因此当您尝试释放它时,它将使程序崩溃。

尝试以下方法:

double* getStuff(double *R_list, int items)
{
  double* results_p = malloc(sizeof((*results_p) * (items + 1));
  if (results_p == NULL)
  {
    // handle error
  }

  for(int i = 0; i < items; i++)
  { 
    res = calculation ; \\do some calculation
    results_p[i] = res;
  }

  printf("C allocated address %p \n", results_p);

  return results_p;
}