使用GC.AddMemoryPressure()防止OutOfMemoryException?

我正在调试一种方法,我们用它来标记具有特定文本的图像,然后再将它们显示在我们的系统中。

标签方法目前看起来像这样:

private static Image TagAsProductImage(Image image) { try { // Prepares the garbage collector for added memory pressure (500000 bytes is roughly 485 kilobytes). // Should solve some OutOfMemoryExceptions. GC.AddMemoryPressure(500000); using (Graphics graphics = Graphics.FromImage(image)) { // Create font. Font drawFont = new Font("Tahoma", image.Width*IMAGE_TAG_SIZE_FACTOR); // Create brush. SolidBrush drawBrush = new SolidBrush(Color.Black); // Create rectangle for drawing. RectangleF drawRect = new RectangleF(0, image.Height - drawFont.GetHeight(), image.Width, drawFont.GetHeight()); // Set format of string to be right-aligned. StringFormat drawFormat = new StringFormat(); drawFormat.Alignment = StringAlignment.Far; // Draw string to screen. graphics.DrawString(TAG_TEXT, drawFont, drawBrush, drawRect, drawFormat); } } // If an out of memory exception is thrown, return the unaltered image. catch(OutOfMemoryException) { GC.RemoveMemoryPressure(500000); return image; } GC.RemoveMemoryPressure(500000); return image; } 

将事物置于上下文中:在从图像服务器检索图像并将其保存到本地缓存(我们的系统与需要相同图片的其他系统共享)之后,将调用此方法。

到达using (Graphics...时,我们遇到了OutOfMemoryExceptions问题using (Graphics... (在标记之前需要从服务器检索图像时,如果图像存在于缓存中,则标记不是问题)。

为了防止/绕过OutOfMemoryException,我尝试了三种不同的方法,虽然它们有效但我并不喜欢它们中的任何一种。

首先我尝试做一个通用的GC.Collect(); 在调用Graphics.FromImage(image)之前(当然),但我不喜欢强制收集,因为它在性能上留下了很大的打击。

我的第二种方法是在catch语句中调用GC.Collect()然后递归调用TagAsProductImage(image)但如果GC无法释放足够的内存,这可能会导致无限循环。

最后我最终得到了上面的代码,我不能说我也喜欢上述代码。

我可以放弃使用GC.Collect()因为从服务中获取图像的整个操作 – >保存 – >标记是相当大的,因此收集的性能影响很小但我真的很喜欢更好的解决方案。

如果有人有这方面的智能解决方案,请分享。

如果您正在寻找一种方法来确保您有足够的内存可用于操作,请使用MemoryFailPoint

有了这个,通过using ,您可以定义一个需要一定内存量的区域。 如果它不可用,它将抛出可恢复的InsufficientMemoryException

有关更多信息,请参阅http://msdn.microsoft.com/en-us/library/system.runtime.memoryfailpoint.aspx 。

你在这里遇到了不同的问题,这段代码使用的内存非常少。 可悲的是,GDI +exception非常糟糕。 使用TaskMgr.exe,进程选项卡进行诊断。 查看+选择列并勾选GDI对象,句柄和用户对象。

如果我的怀疑是正确的,你会看到你的进程的GDI对象计数器在这段代码运行时不断攀升。 当它达到10,000时,Windows决定代码存在根本性的错误,并拒绝再创建句柄。 GDI +然后对它有点g and并报告内存不足错误。 错了,应该是’无法创建句柄’错误。 它没有的错误代码。 .NET无法改善exception。

Anyhoo,原因是你没有在字体和画笔上调用Dispose()。 用using语句包装它们。 这通常不会造成麻烦但你的程序显然使用太少的垃圾收集内存来启动终结器线程。