Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Does Ctypes Structures and POINTERS automatically free the memory when the Python object is deleted?

Tags:

python

ctypes

When using Python CTypes there are the Structures, that allow you to clone c-structures on the Python side, and the POINTERS objects that create a sofisticated Python Object from a memory address value and can be used to pass objects by reference back and forth C code.

What I could not find on the documentation or elsewhere is what happens when a Python object containing a Structure class that was de-referenced from a returning pointer from C Code (that is - the C function alocated memory for the structure) is itself deleted. Is the memory for the original C structure freed? If not how to do it?

Furthermore -- what if the Structure contains Pointers itself, to other data that was also allocated by the C function? Does the deletion of the Structure object frees the Pointers onits members? (I doubt so) Else - -how to do it? Trying to call the system "free" from Python for the Pointers in the Structure is crashing Python for me.

In other words, I have this structure filled up by a c Function call:

class PIX(ctypes.Structure):
    """Comments not generated
    """
    _fields_ = [
        ("w", ctypes.c_uint32),
        ("h", ctypes.c_uint32),
        ("d", ctypes.c_uint32),
        ("wpl", ctypes.c_uint32),
        ("refcount", ctypes.c_uint32),
        ("xres", ctypes.c_uint32),
        ("yres", ctypes.c_uint32),
        ("informat", ctypes.c_int32),
        ("text", ctypes.POINTER(ctypes.c_char)),
        ("colormap", ctypes.POINTER(PIXCOLORMAP)),
        ("data", ctypes.POINTER(ctypes.c_uint32))
    ]

And I want to free the memory it is using up from Python code.

like image 378
jsbueno Avatar asked Dec 29 '10 04:12

jsbueno


1 Answers

The memory is not freed, because Python has no idea if or how it should be freed. Compare these two functions:

void testfunc1(PIX *pix)
{
    static char staticBuffer[256] = "static memory";
    pix->text = staticBuffer;
}

void testfunc2(PIX *pix)
{
    pix->text = (char *)malloc(32);
    strcpy(pix->text, "dynamic memory");
}

Used like this:

pix1, pix2 = PIX(), PIX()
mylib.testfunc1(ctypes.byref(pix1))
mylib.testfunc2(ctypes.byref(pix2))

And then at some point, pix1 and pix2 go out of scope. When that happens, nothing happens to the inner pointers—if they pointed to dynamic memory (as is the case here with pix2 but not pix1), you are responsible for freeing it.

The proper way to solve this problem is, if you allocate dynamic memory in your C code, you should provide a corresponding function that deallocates that memory. For example:

void freepix(PIX *pix)
{
    free(pix->text);
}


pix2 = PIX()
mylib.testfunc2(ctypes.byref(pix2))
...
mylib.freepix(ctypes.byref(pix2))
like image 151
Adam Rosenfield Avatar answered Oct 23 '22 21:10

Adam Rosenfield