You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

OpenCvSharp视频采集与融合场景下内存泄漏问题如何解决

内存泄漏问题原因

  • 未释放OpenCvSharp的Mat对象:capture.Read(image) 和 capture2.Read(image2) 每次读取生成的image、image2都是非托管的Mat资源,你没有主动释放,这是最核心的泄漏来源。
  • SetImageOpacity 方法导致Bitmap泄漏:代码中先给bitimg赋值了从image2.Data创建的Bitmap,紧接着又用SetImageOpacity的返回值覆盖了bitimg,原有的Bitmap没有被Dispose,直接丢失引用造成泄漏。
  • 跨线程操作控件引发的资源泄漏:你在后台线程直接给pictureBox.Image赋值,只有Dispose操作做了Invoke,不符合WinForm控件的线程安全要求,很容易出现旧Image资源没有被正确释放的问题。
  • 资源释放顺序错误:你先Dispose了上一轮的result,再替换pictureBox的Image,实际应该先把pictureBox的Image替换为新的result,再释放旧的Image资源,避免控件正在使用的资源被提前释放,也避免旧资源泄漏。

修复方案

  1. 每次循环结束后主动释放image和image2两个Mat对象,调用Release()方法或者用using包裹Mat的创建。
  2. 调整SetImageOpacity的调用逻辑,临时存储生成的半透明Bitmap,用完后同时释放原始的image2对应的Bitmap和半透明Bitmap。
  3. 所有对pictureBox的操作都放到Invoke里,保证在UI线程执行,调整Image替换和释放的顺序。
  4. 移除无意义的Thread.Sleep调用,避免不必要的线程等待。

修复后代码参考:

while (videoStreamFlag)
{
    if(startFlag)
    {
        Mat image = null;
        Mat image2 = null;
        Bitmap baseBitmp = null;
        Bitmap opacityBmp = null;
        Bitmap result = null;
        try
        {
            image = new Mat();
            image2 = new Mat();
            capture2.Read(image2);
            capture.Read(image);

            if (image.Empty() || image2.Empty())
            {
                videoStreamFlag = false;
                break;
            }

            // 创建底图
            baseBitmp = new Bitmap(image.Width, image.Height, ((image.Width * 3 + 3) / 4) * 4, PixelFormat.Format24bppRgb, image.Data);
            result = new Bitmap(baseBitmp.Width, baseBitmp.Height);

            using (var g = Graphics.FromImage(result))
            {
                g.DrawImageUnscaled(baseBitmp, 0, 0);
                baseBitmp.Dispose(); // 底图用完立刻释放

                // 创建前景图
                baseBitmp = new Bitmap(image2.Width, image2.Height, ((image2.Width * 3 + 3) / 4) * 4, PixelFormat.Format24bppRgb, image2.Data);
                opacityBmp = SetImageOpacity(baseBitmp, Opacity / 100f);
                baseBitmp.Dispose(); // 原始前景图用完释放

                g.DrawImageUnscaled(opacityBmp, 0, 0);
                opacityBmp.Dispose(); // 半透明前景图用完释放
            }

            // UI操作全部放到UI线程执行
            panel.Invoke(new MethodInvoker(() => 
            {
                var oldImg = pictureBox.Image;
                pictureBox.Image = result;
                oldImg?.Dispose(); // 替换后再释放旧图片
            }));
            result = null; // 已经交给pictureBox,不用再手动释放
        }
        catch (Exception ex)
        {
            Console.WriteLine("[ERROR!!!]VideoBlending Error...{0}", ex.Message);
            videoStreamFlag = false;
            // 异常时释放所有未释放的资源
            result?.Dispose();
        }
        finally
        {
            // 确保非托管资源一定释放
            image?.Release();
            image?.Dispose();
            image2?.Release();
            image2?.Dispose();
            baseBitmp?.Dispose();
            opacityBmp?.Dispose();
        }
    }
}

内容的提问来源于stack exchange,提问作者Oguzhan Öztürk

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.04 20:30:05