【问题标题】:C# memory leak after inputing and rotating image Bitmap from USB camera从 USB 摄像头输入和旋转图像位图后 C# 内存泄漏
【发布时间】:2018-10-20 00:58:19
【问题描述】:

我启动从 USB 相机到 C# windows 应用程序的图像帧下载: (使用 Accord 的(即 AForge)VideoCaptureDevice)

// Automatically start inputing each frame from camera:
var videoDevices = new FilterInfoCollection(FilterCategory.VideoInputDevice);
// Select physical USB camera:                 http://accord-framework.net/docs/html/T_Accord_Video_DirectShow_VideoCaptureDevice.htm
videoSource = new VideoCaptureDevice( videoDevices[0].MonikerString, pixelFormat_for_ExhaustiveTemplateMatching);
// Select event handlers:
videoSource.NewFrame += new NewFrameEventHandler( EVENT_camera_frame ); //http://accord-framework.net/docs/html/T_Accord_Video_NewFrameEventArgs.htm

// Start slurpin up them camera frames:
videoSource.Start();

然后,我处理包含来自相机的下一个图像帧的每个事件:

    private static void EVENT_camera_frame(object sender, NewFrameEventArgs camera_frame_event)
    {
        if( latest_frame_buffer_Bitmap != null )
        {
            latest_frame_buffer_Bitmap.Dispose();
        }

        // Allocate camera Bitmap buffer:
        camera_buffer_Bitmap = new Bitmap( 
        // ..rotate and copy raw camera frame image bitmap from camera_frame_Bitmap to camera_buffer_Bitmap: 
        image_rotator_RotateBilinear.Apply(   camera_frame_Bitmap ));       ///////////  2ND BITMAP BUFFER   /////////////

        // Init a Bitmap for size of frame from camera and for conversion from camera native pixel format to comparison compatible format Format24bppRgb:
        latest_frame_buffer_Bitmap = new Bitmap(    camera_frame_Bitmap.Width, 
                                                camera_frame_Bitmap.Height,
                                                System.Drawing.Imaging.PixelFormat.Format24bppRgb);

        // From rotated, camera format image bitmap in camera_frame_Bitmap, convert to Format24bppRgb and copy to latest_frame_buffer_Bitmap:
        using (Graphics gr = Graphics.FromImage( latest_frame_buffer_Bitmap))
        {
            gr.DrawImage( camera_buffer_Bitmap, new Rectangle(0, 0,
                                                                latest_frame_buffer_Bitmap.Width,
                                                                latest_frame_buffer_Bitmap.Height));

            camera_buffer_Bitmap.Dispose();
            // Draw crop rectangle in Live Camera View:
            using( Graphics live_image_Graphics = Graphics.FromImage( latest_frame_buffer_Bitmap ) )
            {
                live_image_Graphics.DrawRectangle( crop_pen, crop_display_rectangle );   /////////////   DRAW CROPPING RECTANGLE   /////////////
            }
            // Show crop rectangle in PictureBox of Live Camera View:
            control_panel.show_camera_crosshairs();    
        } 
camera_frame_Bitmap.Dispose();   // I just tried this, but didn't fix the leak.
    } 

然后,我使用 .BeginInvoke 来“调度”UI 线程来更新 PictureBox:

public  void show_camera_crosshairs()
{
    // Show crosshairs, if requested in camera view:

    // Create pen.
    Pen crosshairs_pen = new Pen(Color.White, 1 );

    int width = Computer_Vision_API.latest_frame_buffer_Bitmap.Width;
    int height = Computer_Vision_API.latest_frame_buffer_Bitmap.Height;

    int top_y = height - 1;
    int bottom_y = 0;
    int left_x = 0;
    int right_x = width - 1;

    // Create points that define line.
    Point crosshair_point_top = new Point( width / 2, top_y );
    Point crosshair_point_bottom = new Point( width / 2, bottom_y );
    Point crosshair_point_left = new Point( 0, height / 2 );
    Point crosshair_point_right = new Point( width-1, height / 2 );

    float[] dashValues = { 4, 2 };
    crosshairs_pen.DashPattern = dashValues;
    // Verticle crosshair:
    Graphics live_image_Graphics = Graphics.FromImage( Computer_Vision_API.latest_frame_buffer_Bitmap );
    live_image_Graphics.DrawLine( crosshairs_pen, crosshair_point_top, crosshair_point_bottom );

    // Horizontal crosshair:
    live_image_Graphics.DrawLine( crosshairs_pen,  crosshair_point_left, crosshair_point_right );
    live_image_Graphics.Dispose();

    // Display latest frame from camera:
    Common.dbg("","","BeginInvoke: update_PictureBox");
    PictureBox_live_camera.BeginInvoke( new update_PictureBox_Delegate( update_PictureBox ));
}

最后,我有 UI 线程更新 PictureBox...

public delegate void update_PictureBox_Delegate(  );

public  void update_PictureBox()
{
    Common.dbg("","","");
    Computer_Vision_API.computer_vision_resource.WaitOne();
    Common.dbg("","","computer_vision_resource");
    PictureBox_live_camera.Image = Computer_Vision_API.latest_frame_buffer_Bitmap;
    PictureBox_live_camera.BackgroundImage = Computer_Vision_API.latest_frame_buffer_Bitmap;
    Computer_Vision_API.computer_vision_resource.ReleaseMutex();           // release use of computer vision Bitmap buffers, etc.
}

看看内存泄漏...

U P D A T E : 我将内存泄漏的原因缩小到这一行:

image_rotator_RotateBilinear.Apply(   camera_frame_Bitmap ));       ///////////  2ND BITMAP BUFFER   /////////////

下面的评论表明锯齿模式根本不会推断出内存泄漏——这只是我的错误假设。这是最新的记忆模式......

【问题讨论】:

  • 你在哪里清理你以前的位图? Bitmap 是一次性的,创建新的时候需要去掉之前的图片。
  • 与 ... latest_frame_buffer_Bitmap.Dispose();和 camera_buffer_Bitmap.Dispose();
  • 好吧,也许我错过了那些。为什么你把你的截图称为内存泄漏?似乎内存会上升一点,然后循环回收。它真的会随着时间的推移而不断增加吗? (很难从屏幕截图中分辨出峰值。)
  • xxbbcc:那么,那只是一种垃圾收集模式?
  • 对不起,我直到现在才看到你的评论。是的,根据您的屏幕截图,这似乎是一种 GC 模式。如果峰值随着时间的推移越来越高,则表明存在内存泄漏。

标签: c# .net image image-processing bitmap


【解决方案1】:

问题不在代码中。 这是我对 Diag Tool 显示的内存模式的误解(上图)。尽管内存使用量在多个事件回调中有所增加,但智能垃圾收集器不会自动处理每个回调。

感谢 xxbbcc 的启发性评论。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-01-10
    • 1970-01-01
    • 1970-01-01
    • 2013-10-01
    • 1970-01-01
    相关资源
    最近更新 更多