C#保存位图的更快方法
我正在开发一个录音应用程序,我能够每秒获得10-15个屏幕截图。 问题是保存所有图像的速度要足够快,这样屏幕截图的队列就不会在RAM中累积并耗尽用户的内存 目前,我可以通过使用两个线程来实现这一点,这两个线程依次保存图像,然后收集垃圾C#保存位图的更快方法,c#,multithreading,bitmap,cpu,streamwriter,C#,Multithreading,Bitmap,Cpu,Streamwriter,我正在开发一个录音应用程序,我能够每秒获得10-15个屏幕截图。 问题是保存所有图像的速度要足够快,这样屏幕截图的队列就不会在RAM中累积并耗尽用户的内存 目前,我可以通过使用两个线程来实现这一点,这两个线程依次保存图像,然后收集垃圾 while (true) { bmp = null; Dispatcher.Invoke(new Action(delegate() { if (images.Count > 0) {
while (true)
{
bmp = null;
Dispatcher.Invoke(new Action(delegate()
{
if (images.Count > 0)
{
bmp = images[0];
images.RemoveAt(0);
}
}));
if (bmp != null)
{
bmp.Save("frames\\" + framesImagesIndex++ + ".png", ImageFormat.Png);
bmp.Dispose();
bmp = null;
GC.Collect();
}
Thread.Sleep(10);
}
问题是,它非常CPU密集,所以我认为它不会在性能较差的系统上工作。这个方法在我的3.31 GHz进程上需要30个CPU
当我将CPU设置为将所有图像写入一个文件,并通过锁定位图的位只写入字节时,我可以将CPU减少到17左右
byte[] rgbValues;
IntPtr ptr;
System.Drawing.Rectangle rect;
System.Drawing.Imaging.BitmapData bmpData;
System.Drawing.Imaging.PixelFormat pxf;
pxf = System.Drawing.Imaging.PixelFormat.Format24bppRgb;
//using(FileStream fs = new FileStream("frames.data", FileMode.OpenOrCreate, FileAccess.Write))
while (true)
{
bmp = null;
Dispatcher.Invoke(new Action(delegate()
{
if (images.Count > 0)
{
bmp = images[0];
images.RemoveAt(0);
}
}));
rect = new System.Drawing.Rectangle(0, 0, bmp.Width, bmp.Height);
bmpData = bmp.LockBits(rect, System.Drawing.Imaging.ImageLockMode.ReadOnly, pxf);
ptr = bmpData.Scan0;
rgbValues = new byte[bmpData.Stride * bmp.Height];
Marshal.Copy(ptr, rgbValues, 0, rgbValues.Length);
fs.Write(rgbValues, 0, rgbValues.Length);
bmp.UnlockBits(bmpData);
bmp.Dispose();
bmp = null;
GC.Collect();
}
这种方法有助于解决CPU问题,但因为速度不够快。图像队列会堆积并使ram过载,因此我不知道还能做些什么来解决这两个问题
还有其他可用的方法吗?首先,使用
而与线程循环。Sleep(x)
非常占用CPU,就像GC.Collect()
和频繁调用新实例一样。
您应该考虑使用线程
Action action;
public void Main()
{
action = new Action(delegate()
{
if (images.Count > 0)
{
bmp = images[0];
images.RemoveAt(0);
}
});
Thread thread = new Thread(SaveBitmap());
thread.Start();
thread.Priority = ThreadPriority.Highest
}
public void SaveBitmap()
{
Dispatcher.Invoke(action);
if (bmp != null)
{
bmp.Save("frames\\" + framesImagesIndex++ + ".png", ImageFormat.Png);
bmp.Dispose();
bmp = null;
}
}
尝试使用上面的方法,或者至少集成一些部分。请记住,您在这个循环的每个迭代中都强制执行垃圾收集。。它是所有世代的完整收藏。当内存变大时,让GC负责清理内存可能会更好(而且这些位图没有根)。记住,GC在开始工作时会挂起所有线程。因此,当所有代都被收集起来,大型对象堆变得支离破碎时,所有东西实际上都停止在这条线上。我对它进行了测试,GC需要0到15毫秒,并且在删除它时不会减少CPU的使用。大部分时间都花在写文件上,即使。。这是一个你并不真正需要的延迟。CPU无疑会因为而关闭,而(true)
。。您是否考虑过将文件写入工作委托给一些线程?或者这是在它自己的线程中运行的?与其专注于保存和清理,不如实施一种方法来限制收集过程?@Okuma.Scott,我不是在寻求帮助,以便在我的录音线程中添加睡眠呼叫。我请求帮助以更有效地保存15 FPS文件。我使用线程,我测试了2个和10个没有while循环的线程。