我有一个使用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,我非常怀疑我正在做这么大的事情,即使它耗尽内存并试图通过重新分配加倍。我也注意到了:
之前我遇到了同样的错误,但是在我评论了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”,而不是。
答案 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来使用它。显然,尝试释放非首先拥有的内存会导致此分配请求。