[英]Constant garbage collection from converting Bitmap to BitmapImage
我的代码本质上是尝试通过不断更新绑定到 UI (WPF) 的 BitmapImage 来创建视频源。 这意味着每秒将多次将位图转换为 BitmapImage。 然而,这会导致持续的垃圾收集(每秒多次),这似乎是一个坏兆头?
位图被正确处理,它只是导致问题的 BitmapImage 部分。 我尝试写入 BitmapImage 而不是创建一个新的,但是一旦冻结它就变成了只读的。 如果我解冻它,我会得到错误:“必须在与 DependencyObject 相同的线程上创建 DependencySource”。
下面是我用来创建位图图像的方法
//CapturedBitmapmapImage bound to the UI
CapturedBitmapImage = BitMap2BitMapImage(bitmap);
//Method for converting Bitmap to BitmapImage
public static BitmapImage BitMap2BitMapImage(Bitmap bitmap)
{
MemoryStream ms = new MemoryStream();
bitmap.Save(ms, System.Drawing.Imaging.ImageFormat.Bmp);
BitmapImage image = new BitmapImage();
image.BeginInit();
ms.Seek(0, SeekOrigin.Begin);
image.StreamSource = ms;
image.EndInit();
image.Freeze();
return image;
}
此方法将保存图像并为每一帧解码,可能会多次分配整个图像缓冲区。 所以也就不足为奇了,它会造成大量的内存分配,并且可能在大对象堆上让事情变得更糟。
要解决此问题,我建议改用WritableBitmap 。 假设您有两个位图的相同大小/颜色空间并且正在运行不安全的代码:
var bitmapData = sourceBitmap.LockBits(
new Rectangle(0, 0, sourceBitmap.Width, sourceBitmap.Height),
System.Drawing.Imaging.ImageLockMode.ReadOnly,
sourceBitmap.PixelFormat);
var sourcePtr = bitmapData.Scan0;
myWriteableBitmap.Lock();
var destPtr = bitmap.BackBuffer;
var totalBytes = bitmapData.Stride * bitmapData.Height * myWriteableBitmap.Format.BitsPerPixel / 8;
Buffer.MemoryCopy((byte*)sourcePtr, (byte*)destPtr, totalBytes, totalBytes);
myWriteableBitmap.Unlock();
sourceBitmap.UnlockBits(bitmapData);
但是您也许可以调用 C memcopy 函数来避免任何实际的指针。 另请注意,您应该在锁定/解锁数据时添加错误处理。
这应该允许您避免分配,除了首先创建位图。 理想情况下,您希望完全避免创建任何新位图,并为图像数据重用任何缓冲区。 但是很难说出如何执行此操作,因为您没有显示位图是如何创建的。
您应该使用曾经分配给 Image 元素的 Source 属性的 WriteableBitmap,而不是为每个帧创建一个新的 BitmapImage。
int frameWidth = ...
int frameHeight = ...
var pixelFormat = PixelFormats.Bgr24; // must match Bitmap.PixelFormat
var writeableBitmap = new WriteableBitmap(
frameWidth, frameHeight, 96, 96, pixelFormat, null);
image.Source = writeableBitmap;
然后,您将像这样从 Bitmap 循环更新 WriteableBitmap(以及 Image 元素):
Bitmap bitmap = ... // a frame
var bitmapData = bitmap.LockBits(
new System.Drawing.Rectangle(0, 0, bitmap.Width, bitmap.Height),
System.Drawing.Imaging.ImageLockMode.ReadOnly, bitmap.PixelFormat);
image.Dispatcher.Invoke(() => writeableBitmap.WritePixels(
new Int32Rect(0, 0, bitmap.Width, bitmap.Height),
bitmapData.Scan0, bitmapData.Stride * bitmapData.Height, bitmapData.Stride));
bitmap.UnlockBits(bitmapData);
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.