2010-11-14 24 views
7

我在這裏問,因爲到目前爲止我還沒有得到OpenCV開發者的任何幫助。我將這個問題簡化爲一個非常簡單的測試用例,所以任何具有CPython背景的人都可以在這裏找到幫助。OpenCV:內存泄漏與Python界面,但不是在C版本

這種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; 

我完全不明白了一切,因爲我從來沒有與C-接口之前曾到Python。但是,我正在尋找的錯誤可能在這段代碼中。

我對不對?或者我應該在哪裏尋找錯誤?我將如何解決它?

(注意:有人看過這個問題的早期版本:我查看了錯誤的代碼,他們的SWIG接口已被棄用,不再使用(但代碼仍然存在於SVN中,這就是爲什麼我把它弄糊塗了所以不考慮interfaces/swig,這個代碼是舊的和不使用。當前的代碼住在modules/python


Upstream bug report: memleak in OpenCV Python CreateHist

回答

2

它已被修復。

更換3周前由jamesb

  • 狀態從接受變更爲設定爲固定

固定的封閉

  • 分辨率r4526

    的範圍參數沒有被釋放,並且範圍上的迭代器未被DECREF處理。迴歸現在通過,原始循環不會泄漏。

  • 0

    我覺得你有垃圾收集問題,你永遠不會離開回路。

    這是否更符合預期?

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

    'CreateHist'返回一個對象。因爲它沒有分配給任何變量,它將在未來的某個時間被釋放(它應該直接進入GC)。正如Python本身所做的那樣,OpenCV必須另外引用一些東西。 – Albert 2011-01-23 16:32:02

    +0

    另外,'cv = None'與問題本身並不真正相關。 'cv'是一個模塊,它在Python的退出時被正確釋放。 – Albert 2011-01-23 16:33:46