[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,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#)
操作系统相关的C ++内存泄漏?
Windows 7清理C ++内存泄漏?
Upstart init正在泄漏内存,你怎么debugging它?
如何检测我的应用程序崩溃在Linux中
有没有一个很好的Valgrind替代Windows?
正如你已经知道,你必须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,copyPixelOperation.sourcecopy); IntPtr hBitmap = screenBmp.GetHbitmap(); bmpGraphics.dispose(); //********** Next line do memory leak result = Imaging.CreateBitmapSourceFromHBitmap(hBitmap,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(); } } }
由于您正在使用位图(屏幕大小),这意味着预期的数据大小超过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 API并手动处理分配。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 [email protected] 举报,一经查实,本站将立刻删除。