在 OpenCV 应用程序中,我如何识别内存泄漏的来源并修复它?
Posted
技术标签:
【中文标题】在 OpenCV 应用程序中,我如何识别内存泄漏的来源并修复它?【英文标题】:In an OpenCV application, how do I identify the source of memory leak and fix it? 【发布时间】:2011-12-21 06:25:48 【问题描述】:我的 OpenCV 应用程序出现内存泄漏。它是一个中等规模的应用程序,有许多类和几千行代码。不知何故,我设法在我的应用程序中产生了一个大的内存泄漏,它在几分钟内吃掉了我所有的 8gb 内存。我在带有 CMake 的 Ubuntu 11.10 上使用 OpenCV C++ 2.3。
这是一个手部追踪应用程序,它同时处理两个视频流,每个摄像头的帧速率约为 15fps。
我尝试使用下面的 valgrind,但是 valgrind 的输出非常大,超出了 shell 可以保存在缓冲区中的数量。我知道我可以将输出保存到日志文件中,但我希望避免阅读所有内容的艰巨任务。这是我使用的 valgrind 命令:
valgrind --tool=memcheck --leak-check=full --show-reachable=yes ./Gibbon
这是 valgrind 输出的最后几行:
==3573== 5,415,576 (1,176 direct, 5,414,400 indirect) bytes in 7 blocks are definitely lost in loss record 2,571 of 2,571
==3573== at 0x4C28F9F: malloc (vg_replace_malloc.c:236)
==3573== by 0x5B2ACD0: cv::fastMalloc(unsigned long) (in /usr/local/lib/libopencv_core.so.2.3.1)
==3573== by 0x5A7FA9D: cvCreateImageHeader (in /usr/local/lib/libopencv_core.so.2.3.1)
==3573== by 0x484538: CameraPGR::convertImageToOpenCV(FlyCapture2::Image*) (CameraPGR.cpp:212)
==3573== by 0x483F52: CameraPGR::grabImage() (CameraPGR.cpp:134)
==3573== by 0x473F86: start() (GibbonMain.cpp:368)
==3573== by 0x4725CC: main (GibbonMain.cpp:108)
==3573==
==3573== LEAK SUMMARY:
==3573== definitely lost: 24,432 bytes in 33 blocks
==3573== indirectly lost: 5,414,640 bytes in 15 blocks
==3573== possibly lost: 2,314,837 bytes in 1,148 blocks
==3573== still reachable: 496,811 bytes in 4,037 blocks
==3573== suppressed: 0 bytes in 0 blocks
==3573==
==3573== For counts of detected and suppressed errors, rerun with: -v
==3573== Use --track-origins=yes to see where uninitialised values come from
==3573== ERROR SUMMARY: 336 errors from 318 contexts (suppressed: 10 from 8)
有什么更好的方法可以解决这个问题?是否有一些工具可以简洁地向我展示哪些函数调用导致了大部分内存分配?如果 valgrind 是答案,我会很感激一些关于如何以更有效的方式使用它的提示,因为我对这个工具完全陌生。
【问题讨论】:
如果我不得不猜测的话,我会说你可能在CameraPGR::grabImage()
附近的某个地方分配内存并且永远不会释放它。
我已经多次查看该功能,找不到那里的问题。明天我会做更多的事情。对于如何改进查找内存泄漏根本原因的过程,您有什么建议吗?
在没有看到任何代码的情况下,真的不可能猜出哪里出了问题。您是否释放了在上述调用堆栈中分配的内存?如果没有,那就是你的问题。
具体来说,既然你打电话给cvCreateImageHeader
,你是不是也打电话给cvReleaseImageHeader
?
不,我没有调用cvReleaseImageHeader
,因为我正在从函数返回图像。然后将图像转换为cv::Mat
。一旦我在主循环中完成使用它,我就会在它上面调用image.release()
。这还不足以释放与此图像相关的所有内存吗?
【参考方案1】:
不是答案,而是建议:从 OpenCV C 接口迁移到 C++。如果使用得当,它将最大限度地减少您现在和将来发生泄漏的机会。它嵌入在对象中的智能指针会自动释放内存。
在最坏的情况下,您会受到性能损失(太多的分配/释放),但这些在分析器中很容易发现。
C++接口正在使用
Mat intead of IplImage,
Point instead of CvPoint,
cv::function() instead of cvFunction.
而且您不必声明指向图像的指针:
Mat src = imread("myfile.jpg");
Mat gray; // note that I do not allocate it.
// This is done automatically in the next functions
cv::cvtColor(src, gray, CV_BGR2GRAY);
imshow("Gray image", gray);
waitKey();
如果你有一些遗留代码,或者使用其他接口的第三方,来回转换很容易:
Mat src(width, height, CV_8UC3);
IplImage* legacyImg;
legacyImg = &(IplImage)src;
其他数据类型(如CvPoint
)会自动转换。 CvSeq
替换为 std::vector<T>
【讨论】:
感谢您的建议。除了大约一年前我从相机中读取图像的部分外,我在其他任何地方都不使用 C 接口。自从我发现 C++ 接口以来,我一直在使用它。不过还是谢谢!以上是关于在 OpenCV 应用程序中,我如何识别内存泄漏的来源并修复它?的主要内容,如果未能解决你的问题,请参考以下文章