我有下一个功能(制作截图)
[DllImport("gdi32.dll")]
private static extern bool DeleteObject(IntPtr hObject);
private Screen SavedScreen { get; } = Screen.PrimaryScreen;
private BitmapSource CopyScreen()
{
try
{
BitmapSource result;
using (
var screenBmp = new Bitmap(SavedScreen.Bounds.Width, SavedScreen.Bounds.Height, PixelFormat.Format32bppArgb))
{
using (Graphics bmpGraphics = Graphics.FromImage(screenBmp))
{
bmpGraphics.CopyFromScreen(SavedScreen.Bounds.X, SavedScreen.Bounds.Y, 0, 0, screenBmp.Size,
CopyPixelOperation.SourceCopy);
IntPtr hBitmap = screenBmp.GetHbitmap();
//********** Next line do memory leak
result = Imaging.CreateBitmapSourceFromHBitmap( hBitmap, IntPtr.Zero, Int32Rect.Empty, BitmapSizeOptions.FromEmptyOptions());
DeleteObject(hBitmap);
}
}
return result;
}
catch (Exception ex)
{
//ErrorReporting ($"Error in CopyScreen(): {ex}");
Debugger.Break();
return null;
}
}并且无法避免内存泄漏,这是调用Imaging.CreateBitmapSourceFromHBitmap的结果。当我在循环中调用这个函数时,这个内存泄漏对我来说非常重要。在WPF应用程序(Windows、c#)中调用
发布于 2016-08-03 08:03:04
正如您已经知道的,您必须Dispose() screenBmp。
您实际上是通过一个using语句调用它的,所以应该可以,但是我怀疑try/catch可能会干扰它。
您是否有机会移动try/catch,以便只包围CopyFromScreen和CreateBitmapSourceFromHBitmap?
从评论中
因为只有在using语句的结束大括号之后,您才确信screenBmp 可以释放,所以我在那里强制使用GC collect
GC.Collect();
return result;而且,似乎没有漏水。
这是我的演示
class Program
{
[DllImport("gdi32.dll")]
private static extern bool DeleteObject(IntPtr hObject);
private static Screen SavedScreen { get; } = Screen.PrimaryScreen;
private static BitmapSource CopyScreen()
{
//try
//{
BitmapSource result;
using (
var screenBmp = new Bitmap(200, 100))
{
using (Graphics bmpGraphics = Graphics.FromImage(screenBmp))
{
bmpGraphics.CopyFromScreen(SavedScreen.Bounds.X, SavedScreen.Bounds.Y, 0, 0, screenBmp.Size,
CopyPixelOperation.SourceCopy);
IntPtr hBitmap = screenBmp.GetHbitmap();
bmpGraphics.Dispose();
//********** Next line do memory leak
result = Imaging.CreateBitmapSourceFromHBitmap(hBitmap, IntPtr.Zero, Int32Rect.Empty, BitmapSizeOptions.FromEmptyOptions());
DeleteObject(hBitmap);
//result = null;
}
}
GC.Collect();
return result;
//}
//catch (Exception ex)
//{
// //ErrorReporting ($"Error in CopyScreen(): {ex}");
// Console.WriteLine(ex.Message);
// Debugger.Break();
// return null;
//}
}
static void Main(string[] args)
{
for (int i = 0; i < 100000; i++)
{
Thread.Sleep(100);
var test = CopyScreen();
}
}
}发布于 2016-08-03 09:03:45
当您使用位图(屏幕大小)时,这意味着预期的数据大小大于85000字节。GC对这些大小的对象进行了不同的处理。这叫陆恭蕙。参见https://blogs.msdn.microsoft.com/maoni/2016/05/31/large-object-heap-uncovered-from-an-old-msdn-article/,它在4.5 https://blogs.msdn.microsoft.com/dotnet/2011/10/03/large-object-heap-improvements-in-net-4-5/中得到了改进,但问题仍然存在。使用高频计算巨大的对象会显著增加应用程序的内存使用量。有两个问题导致了它: 1) GC不能立即工作,它需要时间才能开始释放内存;2) LOH的碎片(请参阅第一篇文章),这就是为什么它没有被释放,这就是为什么您可以看到内存使用量增加了。
可能的解决方案: 1)使用服务器GC和一致GC;手动强制GC。很可能这不会有太大帮助。2)重用现有对象(分配内存),而不是一直在循环中创建新的位图和图形。3)切换到直接使用Windows,手动处理分配。
https://stackoverflow.com/questions/38737349
复制相似问题