Opencv无法免费使用Mat *内存

时间:2016-01-30 12:11:52

标签: c++ opencv matrix memory-leaks

我正在开发一个OpenCV项目,我必须使用Mat * s(我不知道为什么不仅仅是Mat对象!!!)。无论如何,我在内存管理方面遇到了困难。

Mat* m = new Mat ( *MatPointerReturningFunc(..))
or
Mat* m = new Mat ( MatPointerReturningFunc(..)->clone())

当我在visual studio调试模式中执行这些步骤时,我可以看到任务管理器上增加的内存。无论我做了什么,我都无法释放这些矩阵。

m-> release()//不会工作,因为m没有自己的内存空间

*(m-> refcount)= 0 //也没有任何效果。

删除m //未观察到任何效果

我真的被卡住了,我不知道如何修复,相关的内存泄漏问题。

提前感谢您的帮助。

1 个答案:

答案 0 :(得分:0)

绝对可以使用cv :: Mat指针,但是(和所有指针一样)你必须特别注意删除创建的对象,以便再次释放已分配的内存。

在您的示例代码中,不清楚在函数中返回其指针的对象是否会被删除。如果不是这种情况,cv :: Mat像素数据的引用计数将无法按预期工作,此外,一些(次要)内存将被cv :: Mat对象本身泄露。如此简短:对于每个new cv::Mat,必须有delete,因此如果外部函数中有new,则可能需要为其调用delete(如果该函数不会通过稍后的某些智能类功能来实现。更具体的是,Mat* m = new Mat ( *MatPointerReturningFunc(..))将创建一个新的cv :: Mat对象,因为你可以在以后删除它,但是函数返回的指针会丢失。如果要创建新的Mat对象(或者只使用returnedPtr而不创建新对象),请尝试cv::Mat * returnedPtr = MatPointerReturningFunc(..);后跟cv::Mat * m = new cv::Mat(*returnedPtr);

以下是一些示例代码,其中包含2个不同的Mat Ptr返回函数以及在有或没有泄漏的情况下访问它们的一些方法。

重要提一下," best"使用指针的方式通常是智能指针,由OpenCV明确给出。但更好的是不要将指针用于cv :: Mat对象,因为它不易出错,并且没有太多开销。引用计数非常好,您通常不会使用intstd::vectorstd::string等指针作为指针;)

cv::Mat* MatPointerReturningFunc()
{
    // this function allocates new memory by first creating a new cv::Mat object on heap (just some bytes for the Mat header)
    // and second by allocating new reference counted data in that cv::Mat object (pixel memory = 640*480*3 bytes)
    cv::Mat * functionMat = new cv::Mat(480, 640, CV_8UC3, cv::Scalar(rand()%255, rand()%255, rand()%255));

    return functionMat;
}

cv::Mat* MatPointerReturningFunc2(cv::Mat * input)
{
    // this function does not allocate new memory on the heap, just modifies the input data
    cv::circle(*input, cv::Point(320, 240), 100, cv::Scalar(rand() % 255, rand() % 255, rand() % 255), -1);

    return input;
}

int main(int argc, char* argv[])
{

    while (cv::waitKey(0) != 'q')
    {
        cv::Mat * mainMat;
        cv::Mat * anotherMat;

        // this will not leak, because the memory which was allocated in the function, is destroyed afterwards
        //  and the reference counter of the openCV Mat pixel-data is decremented
        if (true)
        {
            mainMat = MatPointerReturningFunc();
            cv::imshow("main", *mainMat);
            delete mainMat;
        }

        // this will leak because the returned Mat object will not be deleted, only the here created one - that's why the reference counting is stuck at one referenced object
        if (false)
        {
            mainMat = new cv::Mat(*MatPointerReturningFunc());
            delete mainMat;
        }

        // this will not leak, since all references to the Mat data are destroyed (the returned Mat and the locally created new Mat)
        if (true)
        {
            mainMat = MatPointerReturningFunc();
            cv::Mat * anotherMat = new cv::Mat(*mainMat);
            cv::imshow("main", *mainMat);
            cv::imshow("another", *anotherMat);
            cv::imshow("another", *anotherMat);
            delete mainMat;
            delete anotherMat;
        }

        // this will not leak because all references are destroyed
        if (true)
        {
            mainMat = MatPointerReturningFunc();
            cv::imshow("main", *mainMat);
            anotherMat = new cv::Mat(mainMat->clone());
            cv::imshow("another", *anotherMat);
            delete mainMat;
            delete anotherMat;
        }


        // now here we work with the second function which does not allocate new memory but only modifies the input matrix
        if (true)
        {
            // first we have to allocate memory, otherwise the input mat can't be modified ;)
            mainMat = new cv::Mat(480, 640, CV_8UC3, cv::Scalar(255, 255, 255));
            cv::imshow("main", *mainMat);

            // this does not leak because the second functions doesn't allocate new memory:
            //  however we have to delete mainMat later, because we created it before.
            if (true)
            {
                anotherMat = MatPointerReturningFunc2(mainMat);
                cv::imshow("another", *anotherMat);
            }

            // this does not leak because we delete the new created Mat object here and the before created mainMat later
            if (true)
            {
                anotherMat = new cv::Mat(*MatPointerReturningFunc2(mainMat));
                cv::imshow("another", *anotherMat);
                delete anotherMat;
            }

            // this does not leak because we delete the new created Mat object here and the before created mainMat later
            //  in fact, this way will allocate new pixel data because of the clone(), but we will free the memory with `delete anotherMat`directly
            if (true)
            {
                anotherMat = new cv::Mat(MatPointerReturningFunc2(mainMat)->clone());
                cv::imshow("another", *anotherMat);
                delete anotherMat;
            }

            // since we created the object and allocated memory, we have to give it free here again
            delete mainMat;
        }

        // in fact, if you WANT to use Pointers with OpenCV Mat objects you should use smart pointers.
        //  OpenCV has its own smart pointers, but I guess you could use any other smart pointers
        // create a Mat object on the heap, allocate pixel data and access all this by a smart pointer!
        cv::Ptr<cv::Mat> smartPtr = new cv::Mat(480, 640, CV_8UC3, cv::Scalar(rand()%255, rand()%255, rand()%255) );
        cv::imshow("smart pointer", *smartPtr);

        // no need to delete the created Mat on the smart pointer, because the smart pointer has its own reference counting
    }

    return 0;
}