OpenCV尝试分配10 Exabyte

时间:2016-08-04 15:31:54

标签: c++ opencv memory-management out-of-memory

我有一个使用opencv的程序。 opencv部分没什么花哨的, 它只是从网络摄像头接收图像,在其中找到一些标记并估计它们的姿势。 但是,我可靠地得到了错误

OpenCV Error: Insufficient memory (Failed to allocate 9892156749154358672 bytes) in OutOfMemoryError, file /home/XYZ/opencv/modules/core/src/alloc.cpp, line 52

这几乎是10 exabyte,我非常怀疑我正在做这么大的事情,即使它耗尽内存并试图通过重新分配加倍。我也注意到了:

  • 它并不总是完全相同的字节数,但总是小于10 exabyte。
  • 它始终发生在程序的同一点上。但是,这部分与opencv没有任何关系。它甚至可以在不同的进程中运行,甚至不会与opencv链接。 (opencv线程通过ros主题发送所需信息。)
  • 以前一直在工作,我没有更改依赖opencv的代码中的一行

之前我遇到了同样的错误,但是在我评论了3行代码之后,基本上(在程序的代码中不依赖于opencv),它无法解释地消失了:

std::cout << "This is an int: " << something->getInt() << std::endl;

所以丝毫没有与opencv有关。因为这个问题已经发生了,并且在评论这些行之后错误消失了,所以我真的很困惑,因为现在导致这种情况。我觉得我的代码中的任何一行都可能是原因,但我无法识别它。这就是为什么不能为您提供重现这一点的最小例子。 我现在将向您展示使用opencv实际执行某些操作的代码段;我删除了执行标记跟踪的部分,假设此处的所有内容都已定义:

int PoseEstimator::trackMarkers(bool estimatePose, int camId, string camParams)
{       
    cv::VideoCapture inputVideo;
    int waitTime = 10;
    inputVideo.open(camId);

    cv::Mat inputImage, inputImageCopy; 
    inputVideo >> inputImage;

    iThreshParam1 = markerDetector.getParams()._thresParam1;
    iThreshParam2 = markerDetector.getParams()._thresParam2;
    cv::namedWindow("threshold");
    cv::createTrackbar("ThresParam1", "threshold", &iThreshParam1, 25, callTrackBarCallback, (void*) &iThreshParam1);
    cv::createTrackbar("ThresParam2", "threshold", &iThreshParam2, 13, callTrackBarCallback, (void*) &iThreshParam2);

      do {
        inputVideo.retrieve(inputImage);
        //This is 620x480, not gigantic

        inputImage.copyTo(inputImageCopy);

        for(unsigned int i = 0; i < markers.size(); i++)
        {
            //Code to track the markers with arucuo library            

            cv::Mat transformMatrix = markerTracker[id].getRTMatrix();
            //This is only a 4x4 matrix



        }

        cv::imshow("input", inputImageCopy);
        cv::imshow("threshold", markerDetector.getThresholdedImage());
        inputImageCopy.release();
        inputImage.release();


        key = cv::waitKey(waitTime);
        if(key == 's')
            waitTime = waitTime == 0 ? 10:0;



    } while (key != 27 && (inputVideo.grab()));

    return 0;
}

我相信整个循环应该为每次交互分配大约2 * 620 * 480 + 4 * 4 * markerCount位,并且在每次新迭代时释放该内存。我不相信这可能是原因,但其他人是否有任何线索或经历过此事?

感谢任何提示!如果需要,我很乐意为您提供更多详细信息。

编辑:我能够最接近缩小范围: 我正在使用boost :: async运行一些东西。

这是在错误发生之前执行的代码:

bool MarkerTracker::doSomething()
{

    boost::unique_future<bool> future = boost::async(boost::launch::async,[this]()
    {

            bool planAgain = true;
            bool success;
            int c = 0;
            int planLimit = 1;
            double totalPlanningTime = 0.0;
            auto startTotal = std::chrono::system_clock::now();
            while(planAgain && c < planLimit && (printf("DEBUG loop\n") || true))
            {

                TrajectoryPlanner planner = TrajectoryPlanner(GetEnv());                    
                std::cout << "planning now " << std::endl;
                auto start = std::chrono::system_clock::now();
                success = planner.plan();
                std::chrono::duration<double> diff = std::chrono::system_clock::now() - start;
                totalPlanningTime += diff.count();


                if(success)
                {
                    planAgain = !robotController->receiveFoundPath(planner.getLastSuccessfullPath());
                    std::cout << "DEBUG sent Path" << std::endl;
                } else
                {
                    planAgain = false;
                }
                c++;
            }


            std::cout << "DEBUG final steps" << std::endl;
            std::chrono::duration<double> diffTotal = std::chrono::system_clock::now() - startTotal;
            std::cout << "DEBUG got time" << std::endl;


            std::cout << std::endl << std::endl << "Planned " << c << " times." << std::endl << std::endl ;



            return success && !planAgain;
        }
    });

    return future.get();


}

那么到底打印的是什么? “DEBUG sent Path”是我看到的最后一件事。我相信代码的下一步是评估循环条件(编辑:最终的增量执行没有问题)。但是,不打印“DEBUG循环”语句(也许编译器会优化它?但它不应该因为它不能知道printf不会有任何副作用)。 我非常怀疑比较int和bool会导致10 exabyte的分配。无论如何,这个陈述应该被评估为假,因此应该打印“DEBUG final steps”,而不是。

1 个答案:

答案 0 :(得分:1)

在C ++中,指针不会自动初始化为0。 TrajectoryPlanner对象的析构函数类似于

DebugDrawer *debugDrawer;

TrajectoryPlanner::~TrajectoryPlanner()
{
    if(debugDrawer)
    {
        delete debugDrawer;
    }
}

但是,指针从未初始化,因此指针被设置为内存中的随机字节。由于C ++将非零的int值计算为true,因此进行了删除调用。 (见Why aren't pointers initialized with NULL by default?

这导致对DebugDrawer析构函数中的cv :: Mat的释放调用,该析构函数来自另一个库,因此我不需要再次链接OpenCV来使用它。显然,尝试释放非首先拥有的内存会导致此分配请求。