OpenCV:Python 接口内存泄漏,但 C 版本没有内存泄漏

发布于 2024-10-01 21:58:07 字数 3176 浏览 0 评论 0原文

我在这里问是因为到目前为止我还没有得到 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代码(OpenCV当前的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 接口。但我正在寻找的错误可能就在这段代码中的某个地方。

我说得对吗?或者我应该在哪里寻找该错误?我该如何解决它?

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


) ros.org/trac/opencv/ticket/674">上游错误报告:OpenCV Python CreateHist 中的 memleak

I am asking here because I haven't gotten any help from the OpenCV developers so far. I reduced the problem to a very simple test case so probably anyone with some background with CPython could help here.

This C code does not leak:

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);
    }
}

This Python code does leak:

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

I searched through the CPython code (of OpenCVs current SVN trunk code) and found this:

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;
}

And from the OpenCV C headers:

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;

I don't exactly understand everything because I never worked with the C-interface to Python before. But probably the bug I am searching for is somewhere in this code.

Am I right? Or where should I search for the bug? How would I fix it?

(Note for people who have seen an earlier version of this question: I looked at the wrong code. Their SWIG interface was deprecated and not used anymore (but the code was still there in SVN, this is why I confused it. So don't look into interfaces/swig, this code is old and not used. The current code lives in modules/python.)


Upstream bug report: memleak in OpenCV Python CreateHist

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

很快妥协 2024-10-08 21:58:07

它已被修复。

由 jamesb 三周前更改

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

已修复r4526

范围参数没有被释放,并且范围上的迭代器没有被 DECREF'ed。现在回归通过了,原始循环不会泄漏。

It has been fixed.

Changed 3 weeks ago by jamesb

  • status changed from accepted to closed
  • resolution set to fixed

Fixed in r4526

The ranges parameters were not being freed, and the iterator over ranges was not being DECREF'ed. Regressions now pass, and original loop does not leak.

冷清清 2024-10-08 21:58:07

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

这是否比预期更有效?

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

I think you have garbage collection issue, in that you never leave the loop.

Does this work more as expected?

while True: 
    cv.CreateHist([40], cv.CV_HIST_ARRAY, [[0,255]], 1)
    cv = None
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文