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

Accord VideoCaptureDevice事件回调中Bitmap帧持续严重内存泄漏求助

解决Accord VideoCaptureDevice的Bitmap内存泄漏问题

嘿,我太懂这种内存持续暴涨的痛苦了!你遇到的问题大概率是两个容易忽略的点:回调参数里的原始Frame没释放,还有Bitmap的所有权转移逻辑没做好。下面给你一步步拆解修复方案:

1. 先搞懂泄漏的根源

Accord的VideoCaptureDevice在触发NewFrame事件时,会自动创建一个新的Bitmap作为camera_frame_event.Frame——这个Bitmap是设备分配的,回调结束后不会自动回收!如果你每次回调都只处理自己的latest_frame_buffer_Bitmap,却不管这个原始Frame,那内存必然会持续泄漏,而且速度会非常快。

另外,如果你的rotation_filter在处理过程中生成了中间Bitmap但没释放,也会雪上加霜。

2. 修正后的回调代码(带完整资源管理)

直接给你改好的代码,每一步都加了注释:

public static Bitmap latest_frame_buffer_Bitmap = null;
private static readonly object frameLock = new object(); // 多线程锁,避免冲突

private static void EVENT_camera_frame(object sender, NewFrameEventArgs camera_frame_event)
{
    // 用using包裹原始Frame,确保不管有没有异常都会被释放
    using (Bitmap originalFrame = camera_frame_event.Frame)
    {
        Bitmap rotatedFrame = null;
        try
        {
            // 执行旋转过滤,生成新的Bitmap
            rotatedFrame = rotation_filter.Apply(originalFrame);

            // 加锁!如果有其他线程在读取latest_frame_buffer_Bitmap,必须避免并发问题
            lock (frameLock)
            {
                // 先释放旧的Bitmap,?.操作符避免空引用
                latest_frame_buffer_Bitmap?.Dispose();
                // 把旋转后的Bitmap赋值给全局变量,同时把rotatedFrame置空转移所有权
                latest_frame_buffer_Bitmap = rotatedFrame;
                rotatedFrame = null;
            }
        }
        finally
        {
            // 如果rotatedFrame没被赋值(比如中途抛异常),就释放它,避免泄漏
            rotatedFrame?.Dispose();
        }
    }
}

3. 额外要注意的细节

  • 多线程安全:如果你的程序里有其他线程在使用latest_frame_buffer_Bitmap(比如UI线程显示它),一定要用锁保护,不然可能出现“Bitmap正在被使用时被Dispose”的崩溃,或者读取到半赋值的Bitmap。
  • 检查rotation_filter的实现:确保你的旋转过滤器内部没有泄漏Bitmap。比如如果它创建了临时Bitmap,一定要用using包裹:
    public Bitmap Apply(Bitmap input)
    {
        using (var tempCanvas = new Bitmap(input.Width, input.Height))
        {
            // 这里写你的旋转逻辑,比如用Graphics绘制
            using (var g = Graphics.FromImage(tempCanvas))
            {
                g.RotateTransform(90);
                g.DrawImage(input, 0, 0);
            }
            // 返回新的Bitmap,不要返回临时的tempCanvas(因为它会被using释放)
            return new Bitmap(tempCanvas);
        }
    }
    
  • 设备停止时的收尾:当你关闭摄像头时,一定要手动清理全局的Bitmap:
    // 停止设备后
    videoCaptureDevice.Stop();
    lock (frameLock)
    {
        latest_frame_buffer_Bitmap?.Dispose();
        latest_frame_buffer_Bitmap = null;
    }
    

为什么之前的代码会爆内存?

你原来的代码只处理了latest_frame_buffer_Bitmap的释放,但每次回调生成的camera_frame_event.Frame都被丢在那里没管——这些Bitmap会一直占着内存,直到GC被迫回收,但GC不会实时处理,所以内存会持续飙升。加上如果旋转过滤器有泄漏,那情况会更严重。

内容的提问来源于stack exchange,提问作者Doug Null

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.27 04:05:32