Commit ac4f4190 by Gael varoquaux

BUG: fix memory leak

The OWNDATA flag was not getting changed, and as a result, there was a
memory leak. I changed strategy, and use a deallocation in the
__dealloc__ method.
parent 3b2990b3
...@@ -13,6 +13,8 @@ http://cython.org for more information ...@@ -13,6 +13,8 @@ http://cython.org for more information
cdef extern from "c_code.c": cdef extern from "c_code.c":
float *compute(int size) float *compute(int size)
from libc.stdlib cimport free
# Import the Python-level symbols of numpy # Import the Python-level symbols of numpy
import numpy as np import numpy as np
...@@ -23,6 +25,43 @@ cimport numpy as np ...@@ -23,6 +25,43 @@ cimport numpy as np
# _always_ do that, or you will have segfaults # _always_ do that, or you will have segfaults
np.import_array() np.import_array()
# We need to build an array-wrapper class to deallocate our array when
# the Python object is deleted.
cdef class ArrayWrapper:
cdef void* data_ptr
cdef int size
cdef set_data(self, int size, void* data_ptr):
""" Constructor for the class.
Mallocs a memory buffer of size (n*sizeof(int)) and sets up
the numpy array.
Parameters:
-----------
n -- Length of the array.
Data attributes:
----------------
data -- Pointer to an integer array.
alloc -- Size of the data buffer allocated.
"""
self.data_ptr = data_ptr
self.size = size
def __array__(self):
cdef np.npy_intp shape[1]
shape[0] = <np.npy_intp> self.size
ndarray = np.PyArray_SimpleNewFromData(1, shape,
np.NPY_INT, self.data_ptr)
return ndarray
def __dealloc__(self):
""" Frees the array. """
free(<void*>self.data_ptr)
def py_compute(int size): def py_compute(int size):
""" Python binding of the 'compute' function in 'c_code.c' that does """ Python binding of the 'compute' function in 'c_code.c' that does
...@@ -32,18 +71,7 @@ def py_compute(int size): ...@@ -32,18 +71,7 @@ def py_compute(int size):
# Call the C function # Call the C function
array = compute(size) array = compute(size)
# Create a C array to describe the shape of the ndarray array_wrapper = ArrayWrapper()
cdef np.npy_intp shape[1] array_wrapper.set_data(size, <void*> array)
shape[0] = <np.npy_intp> size
# Use the PyArray_SimpleNewFromData function from numpy to create a
# new Python object pointing to the existing data
ndarray = np.PyArray_SimpleNewFromData(1, shape,
np.NPY_INT, <void *> array)
# Tell Python that it can deallocate the memory when the ndarray return np.array(array_wrapper)
# object gets garbage collected
# As the OWNDATA flag of an array is read-only in Python, we need to
# call the C function PyArray_UpdateFlags
np.PyArray_UpdateFlags(ndarray, ndarray.flags.num | np.NPY_OWNDATA)
return ndarray
...@@ -4,4 +4,5 @@ ...@@ -4,4 +4,5 @@
# License: BSD # License: BSD
import cython_wrapper import cython_wrapper
print cython_wrapper.py_compute(10) a = cython_wrapper.py_compute(10)
\ No newline at end of file print a
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment