位图图形 CreateBitmapSourceFromHBitmap 内存泄漏
Bitmap Graphics CreateBitmapSourceFromHBitmap memory leak
我想用 WPF 在 Image
容器中显示 Bitmap
。
private void updateImagePreview()
{
Bitmap bmp = new Bitmap(Screen.PrimaryScreen.WorkingArea.Width,
Screen.PrimaryScreen.WorkingArea.Height);
Graphics gr = Graphics.FromImage(bmp);
Image Image_Preview;
while (true)
{
gr.CopyFromScreen(0, 0, 0, 0, new System.Drawing.Size(bmp.Width, bmp.Height));
Image_Preview.Source = loadBitmap(bmp);
}
}
[DllImport("gdi32")]
static extern int DeleteObject(IntPtr o);
public BitmapSource loadBitmap(System.Drawing.Bitmap source)
{
IntPtr ip = source.GetHbitmap();
BitmapSource bs = null;
try
{
bs = System.Windows.Interop.Imaging.CreateBitmapSourceFromHBitmap(
ip, IntPtr.Zero, Int32Rect.Empty,
System.Windows.Media.Imaging.BitmapSizeOptions.FromEmptyOptions());
}
finally
{
DeleteObject(ip);
}
return bs;
}
问题是,这会造成巨大的内存泄漏。泄漏发生在 CreateBitmapSourceFromHBitmap
调用上,并在循环时填充内存,直到超过限制。如果我不使用那个电话,那么泄漏就会消失。知道为什么会这样吗?
尝试在 BitmapSource
上调用 Freeze()
,然后再返回。好像可以帮助释放一些对图片字节的引用。
[DllImport("gdi32")]
static extern int DeleteObject(IntPtr o);
public BitmapSource loadBitmap(System.Drawing.Bitmap source)
{
IntPtr ip = source.GetHbitmap();
BitmapSource bs = null;
try
{
bs = System.Windows.Interop.Imaging.CreateBitmapSourceFromHBitmap(
ip, IntPtr.Zero, Int32Rect.Empty,
System.Windows.Media.Imaging.BitmapSizeOptions.FromEmptyOptions());
}
finally
{
DeleteObject(ip);
}
bs.Freeze();
return bs;
}
如果发生内存泄漏,首先要检查的是是否有任何未处理的 Disposable 对象。
我看到您没有处理两个 Image and Graphics 实例,这可能会导致内存泄漏。
确保在使用结束时将它们丢弃。
例如:在updateImagePreview
方法中
using (Graphics gr = Graphics.FromImage(bmp))
{
....
}
例如:在loadBitmap
方法中
public BitmapSource loadBitmap(System.Drawing.Bitmap source)
{
....
finally
{
DeleteObject(ip);
source.Dispose();
}
return bs;
}
我以某种方式解决了它,但我不完全知道我是如何摆脱泄漏的。我假设调用导致线程中内存泄漏的代码以某种方式解决了该问题。我强烈建议使用评论中提到的 stream wrapper,因为仅使用 MemoryStream 也会导致内存泄漏。无论如何,以下是不会导致上述内存泄漏的代码,并且对我来说很有魅力。
Timer takeScreen;
// This is a button to start the screen capturing
private void Button_Play_Click(object sender, RoutedEventArgs e)
{
int fps = 30;
takeScreen = new Timer(o => addNewImage(), null, 0, 1000 / fps);
}
private void addNewImage()
{
using (Bitmap bmp = new Bitmap(System.Windows.Forms.Screen.PrimaryScreen.Bounds.Width, System.Windows.Forms.Screen.PrimaryScreen.Bounds.Height))
{
using (Graphics gr = Graphics.FromImage(bmp))
{
gr.CopyFromScreen(0, 0, 0, 0, new System.Drawing.Size(bmp.Width, bmp.Height));
Image_Preview.Dispatcher.Invoke(new Action(() => Image_Preview.Source = loadBitmap(bmp)));
}
}
}
public BitmapSource loadBitmap(System.Drawing.Bitmap source)
{
BitmapSource bmpf = null;
using (MemoryStream ms = new MemoryStream())
{
using (WrappingStream ws = new WrappingStream(ms))
{
source.Save(ws, System.Drawing.Imaging.ImageFormat.Bmp);
bmpf = BitmapFrame.Create(ws, BitmapCreateOptions.None, BitmapCacheOption.OnLoad);
}
}
return bmpf;
}
我想用 WPF 在 Image
容器中显示 Bitmap
。
private void updateImagePreview()
{
Bitmap bmp = new Bitmap(Screen.PrimaryScreen.WorkingArea.Width,
Screen.PrimaryScreen.WorkingArea.Height);
Graphics gr = Graphics.FromImage(bmp);
Image Image_Preview;
while (true)
{
gr.CopyFromScreen(0, 0, 0, 0, new System.Drawing.Size(bmp.Width, bmp.Height));
Image_Preview.Source = loadBitmap(bmp);
}
}
[DllImport("gdi32")]
static extern int DeleteObject(IntPtr o);
public BitmapSource loadBitmap(System.Drawing.Bitmap source)
{
IntPtr ip = source.GetHbitmap();
BitmapSource bs = null;
try
{
bs = System.Windows.Interop.Imaging.CreateBitmapSourceFromHBitmap(
ip, IntPtr.Zero, Int32Rect.Empty,
System.Windows.Media.Imaging.BitmapSizeOptions.FromEmptyOptions());
}
finally
{
DeleteObject(ip);
}
return bs;
}
问题是,这会造成巨大的内存泄漏。泄漏发生在 CreateBitmapSourceFromHBitmap
调用上,并在循环时填充内存,直到超过限制。如果我不使用那个电话,那么泄漏就会消失。知道为什么会这样吗?
尝试在 BitmapSource
上调用 Freeze()
,然后再返回。好像可以帮助释放一些对图片字节的引用。
[DllImport("gdi32")]
static extern int DeleteObject(IntPtr o);
public BitmapSource loadBitmap(System.Drawing.Bitmap source)
{
IntPtr ip = source.GetHbitmap();
BitmapSource bs = null;
try
{
bs = System.Windows.Interop.Imaging.CreateBitmapSourceFromHBitmap(
ip, IntPtr.Zero, Int32Rect.Empty,
System.Windows.Media.Imaging.BitmapSizeOptions.FromEmptyOptions());
}
finally
{
DeleteObject(ip);
}
bs.Freeze();
return bs;
}
如果发生内存泄漏,首先要检查的是是否有任何未处理的 Disposable 对象。
我看到您没有处理两个 Image and Graphics 实例,这可能会导致内存泄漏。
确保在使用结束时将它们丢弃。
例如:在updateImagePreview
方法中
using (Graphics gr = Graphics.FromImage(bmp))
{
....
}
例如:在loadBitmap
方法中
public BitmapSource loadBitmap(System.Drawing.Bitmap source)
{
....
finally
{
DeleteObject(ip);
source.Dispose();
}
return bs;
}
我以某种方式解决了它,但我不完全知道我是如何摆脱泄漏的。我假设调用导致线程中内存泄漏的代码以某种方式解决了该问题。我强烈建议使用评论中提到的 stream wrapper,因为仅使用 MemoryStream 也会导致内存泄漏。无论如何,以下是不会导致上述内存泄漏的代码,并且对我来说很有魅力。
Timer takeScreen;
// This is a button to start the screen capturing
private void Button_Play_Click(object sender, RoutedEventArgs e)
{
int fps = 30;
takeScreen = new Timer(o => addNewImage(), null, 0, 1000 / fps);
}
private void addNewImage()
{
using (Bitmap bmp = new Bitmap(System.Windows.Forms.Screen.PrimaryScreen.Bounds.Width, System.Windows.Forms.Screen.PrimaryScreen.Bounds.Height))
{
using (Graphics gr = Graphics.FromImage(bmp))
{
gr.CopyFromScreen(0, 0, 0, 0, new System.Drawing.Size(bmp.Width, bmp.Height));
Image_Preview.Dispatcher.Invoke(new Action(() => Image_Preview.Source = loadBitmap(bmp)));
}
}
}
public BitmapSource loadBitmap(System.Drawing.Bitmap source)
{
BitmapSource bmpf = null;
using (MemoryStream ms = new MemoryStream())
{
using (WrappingStream ws = new WrappingStream(ms))
{
source.Save(ws, System.Drawing.Imaging.ImageFormat.Bmp);
bmpf = BitmapFrame.Create(ws, BitmapCreateOptions.None, BitmapCacheOption.OnLoad);
}
}
return bmpf;
}