1

I have a program that is using opencv. The opencv part does nothing fancy, it just receives images from a webcam, finds some markers in it and estimates their poses. However, I reliably get the error

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

That is almost 10 exabyte, I highly doubt that I am doing anything at this magnitude, even if it runs out of memory and tries to double it with reallocation. I also noticed:

  • It is not always the exact same numer of bytes, but always a bit less than 10 exabyte.
  • It always happends at the same point in the program. However, this part does not have anything to do with opencv. It even runs in a different process and does not even link against opencv. (The opencv thread sends the needed information over a ros topic).
  • It has been working before for a long time, I did not change one line in the code that depends on opencv

I had the same error previously, but it inexplainably dissappeared after I commented 3 lines of code which where basically (in the code of the program that does NOT depend on opencv):

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

So not related to opencv in the slightest. Because this happended, and the error dissappeared after commenting these lines, I am really confused as of what causes this now. I feel like any line of my code might be the reason, but I can't identify it. This why can not provide you with a minimal example to reproduce this. I will now show you the piece of code that actually does something with opencv; I removed the parts that do the marker tracking, assume everything here is defined:

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

I believe that whole loop should allocate roughly 2*620*480+4*4*markerCount bit per interation, and that memory is released on every new iteration. I don't believe this can be the cause, but has anyone else got a clue or experienced this before?

Thanks for any hints! I'll gladly provide you with more details if needed.

Edit: The closest I've been able to come to narrow this down: I am running something using boost::async.

This is the code that gets executed right before the error happens:

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


}

So what gets printed in the end? "DEBUG sent Path" is the last thing I see. I believe the next step in the code would be the evaluation of the loop condition (Edit: The increment in the end is executed without problems). However, the "DEBUG loop" statement is not printed (maybe the compiler optimizes that away? But it shouldn't because it can't know that printf wont have any side effects). I highly doubt that comparing an int and a bool cause the allocation of 10 exabyte. This statement should evaluate to false anyways, so "DEBUG final steps" should be printed, which it is not.

RunOrVeith
  • 4,487
  • 4
  • 32
  • 50
  • 1
    which line of code signals the error? – Mohamed Moanis Aug 04 '16 at 15:38
  • It appears to be none, I'll update the question to the closest I can narrow it down – RunOrVeith Aug 04 '16 at 15:46
  • Can you debug it and check where that happens and the stack trace? – Mohamed Moanis Aug 04 '16 at 16:15
  • I'll try. It is even more unexplainable: The process that runs the openCV parts keeps on running after the error, so it looks like it does not happen there. The process that does not even link OpenCV crashes with errno 11 "Try again". – RunOrVeith Aug 04 '16 at 16:20
  • 1
    "working for a long time" and "disappears when commenting unrelated code" makes it sound a lot like memory corruption somewhere, e.g. writing to memory after freeing it, stack corruption, out-of-bounds array accesses, etc. These sort of bugs produce weird non-deterministic effects that come and go and are often only detected in unrelated parts of the code (or quite a while after they occur). – Cameron Aug 04 '16 at 16:27
  • Ok I found it. The prolem was the destructor of planner, which had something like if(debugDrawer) delete debugDrawer. However, debugDrawer was never initialized and thus had random bytes written in it [link] (http://stackoverflow.com/questions/1910832/why-arent-pointers-initialized-with-null-by-default). That caused the destructor to release a cv::Mat that was not there, which apparently causes this giant allocation request. – RunOrVeith Aug 04 '16 at 16:30

1 Answers1

1

Pointers are not initialized to 0 automatically in C++. The destructor of the TrajectoryPlanner object had something like

DebugDrawer *debugDrawer;

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

However, the pointer was never initialized, thus the pointer was set to random bytes in memory. Since C++ evaluates non-zero ints to true, the delete call was made. (See Why aren't pointers initialized with NULL by default?)

This caused a release call to a cv::Mat inside the DebugDrawer destructor, which is from another library, so I didn't need to link again OpenCV to use it. Apparently trying to release memory that is not owned in the first place causes this allocation request.

Community
  • 1
  • 1
RunOrVeith
  • 4,487
  • 4
  • 32
  • 50