• 如果觉得本站的内容有帮助,可以考虑打赏博主哦!

  • 在本站开通年度VIP,无限制下载本站资源和阅读本站文章

  • 欢迎大家交换友链,可在https://www.stubbornhuang.com/申请友情链接进行友链交换申请!

  • 问题反馈可发送邮件到stubbornhuang@qq.com

  • 工资「喂饱肚子」,副业「养活灵魂」!

  • 计算机图形学与计算几何经典必备书单整理,下载链接可参考:https://www.stubbornhuang.com/1256/

  • 本站由于前段时间遭受到大量临时和国外邮箱注册,所以对可注册的邮箱类型进行了限制!

  • 感谢大家访问本站,希望本站的内容可以帮助到大家!

  • 本站会放置Google广告用于维持域名以及网站服务器费用。

Mediapipe – 关于对Mediapipe C++ SDK使用不当造成的内存泄漏和内存溢出问题的记录

姿态估计 发布于2022-05-09 阅读 5,625次 0次评论 3次点赞 本文共2550个字,阅读需要7分钟。

1 关于对Mediapipe C++ SDK使用不当造成的内存泄漏内存溢出问题的记录

最近在对我的开源项目:https://github.com/HW140701/GoogleMediapipePackageDll进行性能测试的时候发现,检测一帧视频帧的检测延时很长,一帧大概有20-40ms,所以开始了故障代码排查。

定位到的故障代码如下:

    // 1 视频输出结果帧
    mediapipe::Packet packet;
    if (!m_pVideoPoller->Next(&packet))
    {
        return absl::InvalidArgumentError("no next packet");
    }
    if (show_result_image)
    {
        // 从视频输出获取mediapipe::ImageFrame结果
        auto& output_frame = packet.Get<mediapipe::ImageFrame>();

        // 转换mediapipe::ImageFrame为cv::Mat
        cv::Mat output_frame_mat = mediapipe::formats::MatView(&output_frame);

        // 显示cv::Mat结果
        cv::cvtColor(output_frame_mat, output_frame_mat, cv::COLOR_RGB2BGR);
        cv::Mat dst;
        cv::resize(output_frame_mat, dst, cv::Size(output_frame_mat.cols, output_frame_mat.rows));
        cv::imshow("MediapipeHolistic", dst);
        cv::waitKey(1);
    }

上述代码为什么会如此耗时呢?因为获取视频结果帧的耗时很长,性能很差,这一句m_pVideoPoller->Next(&packet)代码获取结果视频帧耗时很长。在正常情况下我们是不需要结果视频帧输出的,只是需要在显示结果视频的时候再输出,所以为了提升性能,将上述代码修改如下:

    // 1 视频输出结果帧
    if (show_result_image)
    {
        mediapipe::Packet packet;

        if (!m_pVideoPoller->Next(&packet))
        {
            return absl::InvalidArgumentError("no next packet");
        }

        // 从视频输出获取mediapipe::ImageFrame结果
        auto& output_frame = packet.Get<mediapipe::ImageFrame>();

        // 转换mediapipe::ImageFrame为cv::Mat
        cv::Mat output_frame_mat = mediapipe::formats::MatView(&output_frame);

        // 显示cv::Mat结果
        cv::cvtColor(output_frame_mat, output_frame_mat, cv::COLOR_RGB2BGR);
        cv::imshow("MediapipeHolistic", output_frame_mat);
    }

修改之后,确实性能有了很大的提升,处理一帧从20-40ms提升到了0ms,但是经过测试,随着处理的视频帧越多,内存一直暴涨到100%,然后程序退出,上述代码出现了严重的内存泄漏和内存溢出问题。

1.2 内存溢出问题的定位与修复

其实最开始出现内存泄漏的问题我也是百思不得骑解,经过两天白用功的试探修改之后还是没有找到问题所在,最后不得不静下心来好好看修改的代码。代码改动的地方就是我们只想要在显示视频帧的时候才去获取结果视频帧,但是我们在初始化模型的时候已经使用m_Graph.AddOutputStreamPoller将video添加到Mediapipe的图中去了,所以,不管这一帧我们是否设置显示输出结果视频帧,结果都会压入到m_pVideoPoller的结果队列中去,而我们又设置不显示结果视频,所以没有办法通过m_pVideoPoller->Next(&packet)拿到packet并释放,导致video的结果视频帧队列越来越大,最后造成内存溢出。

Bingo!

问题解决,修复的代码已经在https://github.com/HW140701/GoogleMediapipePackageDll进行了更新。

1.3 Google Mediapipe对内存溢出问题的解决方案

其实Google在Mediapipe官方文档的Troubleshooting页面也有对内存溢出和内存不足问题进行了解答:https://google.github.io/mediapipe/getting_started/troubleshooting.html#out-of-memory-error

Mediapipe - 关于对Mediapipe C++ SDK使用不当造成的内存泄漏和内存溢出问题的记录-第0张图片

官方文档说内存不足的问题可能是正在运行的MediaPipe图表中累积太多数据包导致的(PS.我也是看到这句话才灵光一现)。而发生累积太多数据包的原因有很多,例如

  • (1)图中的一些计算器根本无法跟上来自实时输入流(如摄像机)的数据包的输入速度
  • (2)一些计算器正在等待永远不会到达的数据包

对于问题 (1),可能需要丢弃一些较旧的旧数据包以处理较新的数据包。
对于问题 (2),可能是一个输入流由于某种原因缺少数据包。设备或计算器可能配置错误或仅偶尔产生数据包。这可能会导致下游计算器等待许多永远不会到达的数据包,这反过来又会导致数据包在它们的一些输入流上累积。

MediaPipe设置CalculatorGraphConfig::max_queue_size通过限制图表的输入来限制在任何输入流上排队的数据包数量。对于实时输入流,在输入流中排队的数据包数量几乎总是为零或一。如果不是这种情况,您可能会看到以下警告消息:

Resolved a deadlock by increasing max_queue_size of input stream

此外,该设置CalculatorGraphConfig::report_deadlock可以设置图运行失败时显示将死锁错误,以便意识到设置max_queue_size进行内存限制。

欢迎扫码关注我的微信公众号,及时获取文章更新

微信公众号二维码

本文作者:StubbornHuang

版权声明:本文为站长原创文章,如果转载请注明原文链接!

原文标题:Mediapipe – 关于对Mediapipe C++ SDK使用不当造成的内存泄漏和内存溢出问题的记录

原文链接:https://www.stubbornhuang.com/2119/

发布于:2022年05月09日 16:56:24

修改于:2023年06月26日 20:12:47

声明:本站所有文章,如无特殊说明或标注,均为本站原创发布。任何个人或组织,在未征得本站同意时,禁止复制、盗用、采集、发布本站内容到任何网站、书籍等各类媒体平台。如若本站内容侵犯了原著者的合法权益,可联系我们进行处理。

文章末尾
上一篇
OpenCV - cv::VideoWriter::fourcc可支持的视频编码格式
OpenCV
下一篇
C++ - std::string替换字符串中所有指定的子字符串
C++
当前分类随机文章推荐

发表评论

您必须 [ 登录 ] 才能发表留言!

关注我们的公众号

微信公众号