代码之家  ›  专栏  ›  技术社区  ›  Albert

OpenCV:Python接口的内存泄漏,但不在C版本中

  •  7
  • Albert  · 技术社区  · 14 年前

    我在这里问是因为到目前为止我还没有从OpenCV开发人员那里得到任何帮助。我把这个问题简化为一个非常简单的测试用例,所以可能任何有CPython背景的人都可以在这里提供帮助。

    此C代码不会泄漏:

    int main() {
        while(true) {
            int hist_size[] = {40};
            float range[] = {0.0f,255.0f};
            float* ranges[] = {range};
            CvHistogram* hist = cvCreateHist(1, hist_size, CV_HIST_ARRAY, ranges, 1);
            cvReleaseHist(&hist);
        }
    }
    

    此Python代码确实泄漏:

    while True: cv.CreateHist([40], cv.CV_HIST_ARRAY, [[0,255]], 1)
    

    我搜索了CPython代码(OpenCVs当前SVN主干代码的)发现:

    struct cvhistogram_t {
      PyObject_HEAD
      CvHistogram h;
      PyObject *bins;
    };
    

    ...

    /* cvhistogram */
    
    static void cvhistogram_dealloc(PyObject *self)
    {
      cvhistogram_t *cvh = (cvhistogram_t*)self;
      Py_DECREF(cvh->bins);
      PyObject_Del(self);
    }
    
    static PyTypeObject cvhistogram_Type = {
      PyObject_HEAD_INIT(&PyType_Type)
      0,                                      /*size*/
      MODULESTR".cvhistogram",                /*name*/
      sizeof(cvhistogram_t),                  /*basicsize*/
    };
    
    static PyObject *cvhistogram_getbins(cvhistogram_t *cvh)
    {
      Py_INCREF(cvh->bins);
      return cvh->bins;
    }
    
    static PyGetSetDef cvhistogram_getseters[] = {
      {(char*)"bins", (getter)cvhistogram_getbins, (setter)NULL, (char*)"bins", NULL},
      {NULL}  /* Sentinel */
    };
    
    static void cvhistogram_specials(void)
    {
      cvhistogram_Type.tp_dealloc = cvhistogram_dealloc;
      cvhistogram_Type.tp_getset = cvhistogram_getseters;
    }
    

    ...

    static PyObject *pycvCreateHist(PyObject *self, PyObject *args, PyObject *kw)
    {
      const char *keywords[] = { "dims", "type", "ranges", "uniform", NULL };
      PyObject *dims;
      int type;
      float **ranges = NULL;
      int uniform = 1;
    
      if (!PyArg_ParseTupleAndKeywords(args, kw, "Oi|O&i", (char**)keywords, &dims, &type, convert_to_floatPTRPTR, (void*)&ranges, &uniform)) {
        return NULL;
      }
      cvhistogram_t *h = PyObject_NEW(cvhistogram_t, &cvhistogram_Type);
      args = Py_BuildValue("Oi", dims, CV_32FC1);
      h->bins = pycvCreateMatND(self, args);
      Py_DECREF(args);
      if (h->bins == NULL) {
        return NULL;
      }
      h->h.type = CV_HIST_MAGIC_VAL;
      if (!convert_to_CvArr(h->bins, &(h->h.bins), "bins"))
        return NULL;
    
      ERRWRAP(cvSetHistBinRanges(&(h->h), ranges, uniform));
    
      return (PyObject*)h;
    }
    

    从OpenCV C头文件中:

    typedef struct CvHistogram
    {
        int     type;
        CvArr*  bins;
        float   thresh[CV_MAX_DIM][2];  /* For uniform histograms.                      */
        float** thresh2;                /* For non-uniform histograms.                  */
        CvMatND mat;                    /* Embedded matrix header for array histograms. */
    }
    CvHistogram;
    

    我并不完全理解所有内容,因为我以前从未使用过Python的C接口。但可能我正在搜索的bug在这段代码中的某个地方。

    我说得对吗?或者我应该在哪里寻找虫子?我该怎么解决?

    (对于那些看过这个问题早期版本的人,请注意:我看错了代码。他们的SWIG接口已被弃用,不再使用(但SVN中的代码仍然存在,这就是我混淆它的原因)。所以不要调查 interfaces/swig ,此代码已过时且未使用。当前代码存在于 modules/python .)


    Upstream bug report: memleak in OpenCV Python CreateHist

    2 回复  |  直到 14 年前
        1
  •  2
  •   Albert    14 年前

    已经修好了。

    三周前由jamesb更改

    • 状态从接受更改为关闭
    • 分辨率设置为固定

    固定在 r4526

    ranges参数没有被释放,ranges上的迭代器也没有被递减。回归现在通过,原始循环也不会泄漏。

        2
  •  0
  •   WombatPM    14 年前

    我认为你有垃圾收集的问题,因为你永远不会离开这个循环。

    这是否比预期的更有效?

    while True: 
        cv.CreateHist([40], cv.CV_HIST_ARRAY, [[0,255]], 1)
        cv = None