OpenCV 尝试分配 10 艾字节
OpenCV tries to allocate 10 Exabyte
我有一个程序正在使用 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 艾字节,我非常怀疑我在做任何如此大的事情,即使它耗尽内存并试图通过重新分配将其加倍。我还注意到:
- 它并不总是完全相同的字节数,但总是略小于 10 艾字节。
- 它总是在程序中的同一点发生。不过这部分和opencv没有任何关系。它甚至在不同的进程中运行,甚至不针对 opencv link。 (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 loop" 语句没有被打印出来(也许编译器优化了它?但它不应该因为它不知道 printf 不会有任何副作用)。
我非常怀疑比较 int 和 bool 会导致分配 10 艾字节。无论如何,该语句的计算结果应该为 false,因此应该打印 "DEBUG final steps",但事实并非如此。
指针在 C++ 中不会自动初始化为 0。
TrajectoryPlanner 对象的析构函数类似于
DebugDrawer *debugDrawer;
TrajectoryPlanner::~TrajectoryPlanner()
{
if(debugDrawer)
{
delete debugDrawer;
}
}
但是,指针从未被初始化,因此指针被设置为内存中的随机字节。由于 C++ 将非零整数计算为真,因此进行了删除调用。 (参见 Why aren't pointers initialized with NULL by default?)
这导致对来自另一个库的 DebugDrawer 析构函数内部的 cv::Mat 的释放调用,因此我不需要再次 link OpenCV 来使用它。显然,首先尝试释放不属于自己的内存会导致此分配请求。
我有一个程序正在使用 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 艾字节,我非常怀疑我在做任何如此大的事情,即使它耗尽内存并试图通过重新分配将其加倍。我还注意到:
- 它并不总是完全相同的字节数,但总是略小于 10 艾字节。
- 它总是在程序中的同一点发生。不过这部分和opencv没有任何关系。它甚至在不同的进程中运行,甚至不针对 opencv link。 (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 loop" 语句没有被打印出来(也许编译器优化了它?但它不应该因为它不知道 printf 不会有任何副作用)。 我非常怀疑比较 int 和 bool 会导致分配 10 艾字节。无论如何,该语句的计算结果应该为 false,因此应该打印 "DEBUG final steps",但事实并非如此。
指针在 C++ 中不会自动初始化为 0。 TrajectoryPlanner 对象的析构函数类似于
DebugDrawer *debugDrawer;
TrajectoryPlanner::~TrajectoryPlanner()
{
if(debugDrawer)
{
delete debugDrawer;
}
}
但是,指针从未被初始化,因此指针被设置为内存中的随机字节。由于 C++ 将非零整数计算为真,因此进行了删除调用。 (参见 Why aren't pointers initialized with NULL by default?)
这导致对来自另一个库的 DebugDrawer 析构函数内部的 cv::Mat 的释放调用,因此我不需要再次 link OpenCV 来使用它。显然,首先尝试释放不属于自己的内存会导致此分配请求。