title: Memory Leak in C-extension for Python
body: <p>This is the first time I am writing a C-extension for python and you can see my ugly and probably super inefficient C++ implementation of a convolution. I have a problem with the memory management. Each time I call this function in python it consumes about 500MB of memory (for a batch of size 100x112x112x3 and a kernel of size 3x3x3x64) and doesn't free it afterwards. Do I have do take care about reference counting, even if this is not a class-method? Or do I have to free up memory manually somewhere in the code? Note that I excluded all the error checks for a better overview. Thanks.</p>
  
  <pre><code>PyObject* conv2d(PyObject*, PyObject* args)
  
  {
      PyObject* data;
      PyObject* shape;
      PyObject* kernel;
      PyObject* k_shape;
      int stride;
  
      PyArg_ParseTuple(args, "OOOOi", &amp;data, &amp;shape, &amp;kernel, &amp;k_shape, &amp;stride);
  
      Py_ssize_t dims = PyTuple_Size(shape);
      Py_ssize_t kernel_dims = PyTuple_Size(k_shape);
  
      int shape_c[3];
      int k_shape_c[4];
  
      for (int i = 0; i &lt; kernel_dims; i++)
      {
          if (i &lt; dims)
          {
              shape_c[i] = PyLong_AsLong(PyTuple_GetItem(shape, i));
          }
          k_shape_c[i] = PyLong_AsLong(PyTuple_GetItem(k_shape, i));
      }
  
      PyObject* data_item, kernel_item;
      PyObject* ret_array = PyList_New(0);
      double conv_val, channel_sum;
  
      for (int oc = 0; oc &lt; k_shape_c[3]; oc++)
      {
          for (int row = 0; row &lt; shape_c[0]; row += stride)
          {
              for (int col = 0; col &lt; shape_c[1]; col += stride)
              {
                  channel_sum = 0;
                  for (int ic = 0; ic &lt; shape_c[2]; ic++)
                  {
                      conv_val = 0;
                      for (int k_row = 0; k_row &lt; k_shape_c[0]; k_row++)
                      {
                          for (int k_col = 0; k_col &lt; k_shape_c[1]; k_col++)
                          {
                              data_item = PyList_GetItem(data, row + k_row);
                              if (!data_item)
                              {
                                  PyErr_Format(PyExc_IndexError, "Index out of bounds");
                                  return NULL;
                              }
                              data_item = PyList_GetItem(data_item, col + k_col);
                              data_item = PyList_GetItem(data_item, ic);
                              kernel_item = PyList_GetItem(kernel, k_row);
                              kernel_item = PyList_GetItem(kernel_item, k_col);
                              kernel_item = PyList_GetItem(kernel_item, ic);
                              kernel_item = PyList_GetItem(kernel_item, oc);
                              conv_val += PyFloat_AsDouble(data_item) * PyFloat_AsDouble(kernel_item);
                          }
                      }
                      channel_sum += conv_val;
                  }
                  PyList_Append(ret_array, PyFloat_FromDouble(channel_sum));
              }
          }
      }
      return ret_array;
  }
  </code></pre>