ctypes可能发生内存泄漏

时间:2018-08-17 16:19:48

标签: python python-3.x memory-leaks ctypes

我正在使用一些使用ctypes的库。该库有其自己的方法来处理堆内存,因此在C中,我将执行以下操作:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "intcall.h"

int main(void) {
    long status = -1;
    char host[10] = "xx.x.x.xx";
    char user[7] = "xxxxxx";
    char pass[7] = "xxxxxx";
    char acc[10] = "xxxxxxxxx";
    long sess = ic_universe_session(host, user, pass, acc, &status, NULL);
    if (status == 0)
    {
        char sub_name[14] = "PRUEBA_XXXXXX";
        long sub_name_len = 13;
        unsigned char param1_txt[5] = "AAAA";
        long size1 = 5;
        long num_params = 2;
        //void * FAR PASCAL ic_malloc ic_proto((LPLONG));
        char* param1 = ic_malloc(&size1);
        memcpy(param1, param1_txt, size1);
        /*  typedef struct icstring {
                long len;
                unsigned char * text;
            } ICSTRING; */
        ICSTRING icstr1;
        icstr1.len = size1; icstr1.text = param1;
        ICSTRING icstr2;
        icstr2.len = 0;
        ic_subcall(sub_name, &sub_name_len, &status, &num_params, &icstr1, &icstr2);
        //void FAR PASCAL ic_free ic_proto((void *));
        ic_free(icstr1.text);
        ic_free(icstr2.text);
    }
    return EXIT_SUCCESS;
}

库可以释放并重新分配我传递给它的指针,所以这就是为什么我需要释放icstr1.text而不是ic_malloc的返回指针param1的原因。

在python中,类似的示例如下:

subrutina = 'PRUEBA_XXXXXX'
argumento = 'AAAA'
num_params = 2
argumentos_tipo = [c_char_p, POINTER(c_long), POINTER(c_long), POINTER(c_long)]
self.__U2_C_INTERFACE.ic_calloc.argtypes = [POINTER(c_long)]
self.__U2_C_INTERFACE.ic_free.argtypes = [ctypes.c_voidp]
self.__U2_C_INTERFACE.ic_subcall.argtypes = argumentos_tipo
sub_name_in = c_char_p(bytes(subrutina, self.__sistema_codificacion))
sub_name_len_in = c_long(len(subrutina))
num_params_len_in = c_long(num_params)
code = c_long(0)
p_in = [None] * num_params
mem_alloc = [c_char_p(0)] * num_params
byte_param = bytes(argumento, self.__sistema_codificacion)
byte_size = len(byte_param)
p_in[0] = ICString(c_long(0))
p_in[0].len = c_long(byte_size)
mem_alloc[0] = c_char_p(self.__U2_C_INTERFACE.ic_calloc(byref(c_long(byte_size + 1))))
tam = byte_size * sizeof(ctypes.c_char)
ctypes.memmove(mem_alloc[0], byte_param, tam)
p_in[0].text = mem_alloc[0]
p_in[1] = ICString(c_long(0))
self.__U2_C_INTERFACE.ic_subcall(sub_name_in,
                                 byref(sub_name_len_in),
                                 byref(code),
                                 byref(num_params_len_in),
                                 *[byref(n) for n in p_in])
if int(code.value) != 0:
    err_msg = 'Error subrutina %s: %s' % (subrutina, UniverseConstants.error_message(code.value))
    from pyuniverse.pyuniverse.UniverseExceptions import UniverseCommandException
    raise UniverseCommandException(err_msg)
# copiar los resultados
for idx, parametro in enumerate(p_in):
    print(p_in[idx].text)
    # if p_in[idx].len > 0:
    #     temp = ctypes.cast(p_in[idx].text, ctypes.c_void_p)
    #     self.__U2_C_INTERFACE.ic_free(temp)

但是对ic_free的调用在堆中造成了麻烦:进程结束,退出代码-1073740940(0xC0000374)。这意味着“堆损坏异常0xC0000374”

我尝试使用pympler使用更多输入参数来跟踪内存使用情况。通过两个参数,我得到了:

                                 types |   # objects |   total size
================================================ | =========== | ============
                                    <class 'dict |           4 |    640     B
                  <class '_ctypes.PyCPointerType |           1 |    492     B
  <class 'ctypes.CDLL.__init__.<locals>._FuncPtr |           4 |    480     B
              <class 'builtin_function_or_method |           7 |    252     B
                                    <class 'list |           5 |    236     B
                                   <class 'tuple |           5 |    184     B
                                 <class 'StgDict |           1 |    148     B
                                    <class 'type |           0 |    144     B
                                     <class 'str |           3 |    127     B
                       <class 'getset_descriptor |           2 |     80     B
                                 <class 'weakref |           1 |     44     B
                                     <class 'int |           1 |     16     B

并带有十个参数:

                                           types |   # objects |   total size
================================================ | =========== | ============
                                    <class 'dict |           4 |    640     B
                  <class '_ctypes.PyCPointerType |           1 |    492     B
  <class 'ctypes.CDLL.__init__.<locals>._FuncPtr |           4 |    480     B
              <class 'builtin_function_or_method |           7 |    252     B
                                    <class 'list |           5 |    268     B
                                   <class 'tuple |           5 |    184     B
                                 <class 'StgDict |           1 |    148     B
                                    <class 'type |           0 |    144     B
                                     <class 'str |          11 |    401     B
                       <class 'getset_descriptor |           2 |     80     B
                                 <class 'weakref |           1 |     44     B
                                     <class 'int |           1 |     16     B

主要区别在于“ str”类:

Two params: <class 'str |           3 |    127     B
Ten params: <class 'str |          11 |    401     B

该内存将由python的垃圾收集器处理吗?我想念什么吗?我在pympler中看不到一些内存泄漏吗?

0 个答案:

没有答案