Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/146.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ Opencv无法释放Mat*内存_C++_Opencv_Matrix_Memory Leaks - Fatal编程技术网

C++ Opencv无法释放Mat*内存

C++ Opencv无法释放Mat*内存,c++,opencv,matrix,memory-leaks,C++,Opencv,Matrix,Memory Leaks,我正在做一个OpenCV项目,我必须使用Mat*s(我不知道为什么不简单地使用Mat对象!!!)。无论如何,我在内存管理方面遇到了困难 Mat* m = new Mat ( *MatPointerReturningFunc(..)) or Mat* m = new Mat ( MatPointerReturningFunc(..)->clone()) 当我在VisualStudio调试模式下执行这些步骤时,我可以看到任务管理器上内存的增加。然而,无论我做了什么,我都无法释放这些矩阵的内存

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

Mat* m = new Mat ( *MatPointerReturningFunc(..))
or
Mat* m = new Mat ( MatPointerReturningFunc(..)->clone())
当我在VisualStudio调试模式下执行这些步骤时,我可以看到任务管理器上内存的增加。然而,无论我做了什么,我都无法释放这些矩阵的内存

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

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

删除m//未观察到任何影响

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


提前感谢您的帮助。

使用cv::Mat指针肯定是可行的,但是(与所有指针一样),您必须格外小心删除创建的对象,以便再次释放分配的内存

在示例代码中,不清楚函数中返回指针的对象是否会被删除。如果情况并非如此,cv::Mat像素数据的引用计数将无法按预期工作,此外,cv::Mat对象本身将泄漏一些(次要)内存。简而言之:对于每个
new cv::Mat
都必须有一个
delete
,因此如果外部函数中有一个
new
,可能您必须为它调用一个
delete
(如果该函数以后没有通过某些智能类功能本身执行)。更具体地说,
Mat*m=new Mat(*MatPointerReturningFunc(..)
将创建一个新的cv::Mat对象,该对象可以在以后删除,但函数返回的指针丢失。Try
cv::Mat*returnedPtr=MatPointerReturningFunc(…)后接
cv::Mat*m=新的cv::Mat(*returnedPtr)如果要创建新的Mat对象(或只使用returnedPtr而不创建新对象)

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

值得一提的是,使用指针的“最佳”方式通常是智能指针,这是OpenCV明确给出的。但更好的是不要为cv::Mat对象使用指针,因为它不太容易出错,并且没有太多开销。引用计数非常好,通常不使用
int
std::vector
std::string
作为指针;)

cv::Mat*MatPointerReturningFunc()
{
//此函数通过首先在堆上创建一个新的cv::Mat对象(仅为Mat头分配一些字节)来分配新内存
//其次,在cv::Mat对象中分配新的引用计数数据(像素内存=640*480*3字节)
cv::Mat*functionMat=新的cv::Mat(480640,cv_8UC3,cv::Scalar(rand()%255,rand()%255,rand()%255));
返回函数矩阵;
}
cv::Mat*MatPointerReturningFunc2(cv::Mat*input)
{
//此函数不在堆上分配新内存,只修改输入数据
cv::circle(*输入,cv::Point(320240),100,cv::Scalar(rand()%255,rand()%255,rand()%255),-1);
返回输入;
}
int main(int argc,char*argv[])
{
而(cv::waitKey(0)!='q')
{
cv::Mat*主Mat;
cv::Mat*anotherMat;
//这不会泄漏,因为在函数中分配的内存随后会被销毁
//并且减少openCV Mat像素数据的参考计数器
如果(真)
{
mainMat=MatPointerReturningFunc();
cv::imshow(“主”,*mainMat);
删除mainMat;
}
//这将泄漏,因为返回的Mat对象不会被删除,而只会在此处创建一个-这就是为什么引用计数停留在一个引用对象上
if(false)
{
mainMat=new cv::Mat(*MatPointerReturningFunc());
删除mainMat;
}
//这不会泄漏,因为对Mat数据的所有引用都已销毁(返回的Mat和本地创建的新Mat)
如果(真)
{
mainMat=MatPointerReturningFunc();
cv::Mat*anotherMat=新cv::Mat(*mainMat);
cv::imshow(“主”,*mainMat);
cv::imshow(“另一个”,anotherMat);
cv::imshow(“另一个”,anotherMat);
删除mainMat;
删除anotherMat;
}
//这不会泄漏,因为所有引用都已销毁
如果(真)
{
mainMat=MatPointerReturningFunc();
cv::imshow(“主”,*mainMat);
anotherMat=new cv::Mat(mainMat->clone());
cv::imshow(“另一个”,anotherMat);
删除mainMat;
删除anotherMat;
}
//现在我们使用第二个函数,它不分配新内存,只修改输入矩阵
如果(真)
{
//首先我们必须分配内存,否则无法修改输入垫;)
mainMat=新的cv::Mat(480640,cv_8UC3,cv::Scalar(255,255,255));
cv::imshow(“主”,*mainMat);
//这不会泄漏,因为第二个函数不分配新内存:
//但是,我们必须在以后删除mainMat,因为我们以前创建过它。
如果(真)
{
anotherMat=MatPointerReturningFunc2(主MAT);
cv::imshow(“另一个”,anotherMat);
}
//这不会泄漏,因为我们在此处删除了新创建的Mat对象,并在稍后删除了之前创建的mainMat对象
如果(真)
{
anotherMat=新cv::Mat(*MatPointerReturningFunc2(mainMat));
cv::imshow(“另一个”,anotherMat);
删除anotherMat;
}
//这不会泄漏,因为我们在此处删除了新创建的Mat对象,并在稍后删除了之前创建的mainMat对象
//事实上,这种方式将分配新的像素
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;
}