C# 两个线程使用 "new bitmap()" 和笔记本电脑卡住



我的程序有两个线程,从两个摄像头抓取数据,每个线程将用于更新一个PictureBox:

    private void StartGrabLoop()
    {
        m_grabThread = new BackgroundWorker();
        m_grabThread.ProgressChanged += new ProgressChangedEventHandler(UpdateUI);
        m_grabThread.DoWork += new DoWorkEventHandler(GrabLoop);
        m_grabThread.WorkerReportsProgress = true;
        m_grabThread.RunWorkerAsync();
    }

    private void StartGrabLoop1()
    {
        m_grabThread1 = new BackgroundWorker();
        m_grabThread1.ProgressChanged += new ProgressChangedEventHandler(UpdateUI1);
        m_grabThread1.DoWork += new DoWorkEventHandler(GrabLoop1);
        m_grabThread1.WorkerReportsProgress = true;
        m_grabThread1.RunWorkerAsync();
    }

    private void GrabLoop(object sender, DoWorkEventArgs e)
    {
        BackgroundWorker worker = sender as BackgroundWorker;
        while (m_grabImages)
        {
            try
            {
                m_camera.RetrieveBuffer(m_rawImage);
            }
            catch (FC2Exception ex)
            {
                Debug.WriteLine("Error: " + ex.Message);
                continue;
            }
            lock (this)
            {
                m_rawImage.Convert(PixelFormat.PixelFormatBgr, m_processedImage);
            }
            worker.ReportProgress(0);
        }
        m_grabThreadExited.Set();
    }

    private void GrabLoop1(object sender, DoWorkEventArgs e)
    {
        BackgroundWorker worker = sender as BackgroundWorker;
        while (m_grabImages1)
        {
            try
            {
                m_camera1.RetrieveBuffer(m_rawImage1);
            }
            catch (FC2Exception ex)
            {
                Debug.WriteLine("Error: " + ex.Message);
                continue;
            }
            lock (this)
            {
                m_rawImage1.Convert(PixelFormat.PixelFormatBgr, m_processedImage1);
            }
            worker.ReportProgress(0);
        }
        m_grabThreadExited1.Set();
    }
 private void UpdateUI(object sender, ProgressChangedEventArgs e)
        {
            Bitmap source = m_processedImage.bitmap;
            Bitmap resized = new Bitmap(source, source.Width / zoom, source.Height / zoom);
            pictureBox1.Image = resized;
            pictureBox1.Invalidate();
}
 private void UpdateUI1(object sender, ProgressChangedEventArgs e)
        {
            Bitmap source = m_processedImage.bitmap;
            Bitmap resized = new Bitmap(source, source.Width / zoom, source.Height / zoom);
            pictureBox2.Image = resized;
            pictureBox2.Invalidate();
}

诀窍是它可以在我的桌面上运行得很好。 但是我的笔记本电脑上有内存问题,要么显示白色图像,要么忙于崩溃。我做了很多研究并尝试了dispose((或System.GC.Collect((; System.GC.WaitForPendingFinalizers((;它们都不起作用,有人可以帮助我吗?我使用"新位图"的原因是因为我想简单的缩放功能......

制作新图像而不链接到旧图像总是更好的;它有助于垃圾回收更好地运行。此外,在放入新版本时显式释放旧版本。

private void UpdateUI(object sender, ProgressChangedEventArgs e)
{
    Bitmap source = m_processedImage.bitmap;
    Bitmap resized = CreateWithNewSize(source, source.Width / zoom, source.Height / zoom);
    // Save reference to old image in the control
    Image oldImg = pictureBox1.Image;
    pictureBox1.Image = resized;
    // specifically dispose old image to avoid memory usage buildup
    if (oldImg != null)
    {
        try{ oldImg.Dispose(); }
        catch { /* Ignore; won't help much to process this */ }
    }
    // Request refresh.
    pictureBox1.Invalidate();
}

。并对 pictureBox2 执行相同的操作。但是,如 InBetween 所述,您可能需要在工作线程和 UI 线程之间设置正确的通信,可能使用委托。在这种情况下,我Save reference to old image注释下的所有代码可能都应该放在委托调用的函数中,以替换 UI 控件上的图像。

调整大小的方法相当简单:

public static Bitmap CreateWithNewSize(Image image, Int32 newWidth, Int32 newHeight)
{
    Bitmap bp = new Bitmap(newWidth, newHeight, PixelFormat.Format32bppArgb);
    using (Graphics gr = Graphics.FromImage(bp))
        gr.DrawImage(image, new Rectangle(0, 0, newWidth, newHeight));
    return bp;
}

m_rawImage1.Convert调用中,在替换它之前,可能应该在m_processedImage1调用相同的图像释放代码。由于此新代码将为您的 UI 制作干净的未链接副本,因此此释放也不会造成任何问题。

最新更新