gpt4 book ai didi

c# - 图像处理循环中的内存异常(需要比 GC.collect 更好的解决方案)

转载 作者:太空狗 更新时间:2023-10-30 00:48:05 32 4
gpt4 key购买 nike

我正在制作一个小应用程序,它在 Windows 窗体中显示实时网络摄像头,并且还存储带水印的图像以按指定的时间间隔驱动(最终目标是创建延时视频)。

我正在使用 AForge 库进行图像和视频处理。

我遇到了问题,似乎存在内存泄漏,即使我尝试确保在每个发生图像处理的位置都使用“using”语句。

下面是发生图像处理的代码(NewFrame 事件)

    private void Video_NewFrame(object sender, NewFrameEventArgs eventArgs)
{
try
{
if (ImageProcessing) // If the previous frame is not done processing, let this one go
return;
else
ImageProcessing = true;

using (Bitmap frame = (Bitmap)eventArgs.Frame)
{
// Update the GUI picturebox to show live webcam feed
Invoke((Action)(() =>
{
webcam_PictureBox.Image = (Bitmap)frame.Clone();
}));

// During tests, store images to drive at a certain interval
if (ImageStoreTimer.Elapsed.TotalSeconds > ImageStoreTime)
{
DateTime dt = DateTime.Now;

using (Graphics graphics = Graphics.FromImage(frame))
{
PointF firstLocation = new PointF(frame.Width / 2, frame.Height / 72);
PointF secondLocation = new PointF(frame.Width / 2, frame.Height / 15);

StringFormat drawFormat = new StringFormat();
drawFormat.Alignment = StringAlignment.Center;

using (Font arialFont = new Font("Arial", 15))
{
graphics.DrawString(dt.ToString(), arialFont, Brushes.Red, firstLocation, drawFormat);
graphics.DrawString(Pressure.ToString("F0") + " mbar", arialFont, Brushes.Red, secondLocation, drawFormat);
}
}

// Place images in a folder with the same name as the test
string filePath = Application.StartupPath + "\\" + TestName + "\\";
// Name images by number 1....N
string fileName = (Directory.GetFiles(filePath).Length + 1).ToString() + ".jpeg";

frame.Save(filePath + fileName, ImageFormat.Jpeg);
ImageStoreTimer.Restart();
}
}
//GC.Collect(); <----- I dont want this
}
catch
{
if (ProgramClosing == true){}
// Empty catch for exceptions caused by the program being closed incorrectly
else
throw;
}
finally
{
ImageProcessing = false;
}
}

现在,当运行该程序时,我看到内存使用量上下波动,通常在下降之前达到大约 900MB。但是偶尔会涨到2GB。有时,我什至会在这一行遇到内存不足的异常:

Graphics graphics = Graphics.FromImage(frame)

因此,在花了一个小时左右的时间尝试 reshape 代码并查找我的内存泄漏之后,我终于尝试了代码中注释掉的 GC.Collect 行(羞耻)。在那之后,我的内存使用量保持不变,低于 60MB。而且我可以毫无问题地运行该程序 24 小时。

所以我阅读了一些关于 GC.Collect 的内容,它有多糟糕,例如,在程序中经常执行它可能需要大量的处理能力。但是当我比较我的程序使用的 CPU 能力时,无论我注释掉还是保留它,它都没有真正改变。但是如果我在新帧事件结束时收集,内存问题就消失了。

我想为我的问题找到一个不涉及 GC.collect 函数的解决方案,因为我知道这是糟糕的编程习惯,我应该找到潜在的问题根源。

提前谢谢大家!

最佳答案

我不擅长 win 表单,但我认为这一行:

webcam_PictureBox.Image = (Bitmap)frame.Clone();

将保留以前的图像未处理,这会泄漏内存(Bitmap 持有的非托管内存)。由于 Bitmap 具有终结器 - 它会在未来某个时间被 GC 回收(或者当您调用 GC.Collect 时),但正如您已经了解的那样 - 在这种情况下依赖 GC 并不是一个好习惯.所以尝试这样做:

if (webcam_PictureBox.Image != null)
webcam_PictureBox.Image.Dispose();
webcam_PictureBox.Image = (Bitmap)frame.Clone();

Larse 的合理评论:当图像仍被分配给 PictureBox.Image 时最好不要处理图像,因为谁知道呢,也许 PictureBox 控件会用分配新图像时使用旧图像。那么替代方案是:

var oldImage = webcam_PictureBox.Image;
webcam_PictureBox.Image = (Bitmap)frame.Clone();
if (oldImage != null)
oldImage.Dispose();

关于c# - 图像处理循环中的内存异常(需要比 GC.collect 更好的解决方案),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50058755/

32 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com