我正在调试一种方法,我们用它来标记带有特定文字的图像,然后再将它们显示在我们的系统中。
标签方法目前看起来像这样:
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;
}
将事物置于上下文中:在从我们的图像服务器检索图像并将其保存到本地缓存(我们的系统与需要相同图片的其他系统共享)之后调用此方法。
我们在到达OutOfMemoryExceptions
时遇到using (Graphics...
问题(在标记之前需要从服务器检索图像时,如果图像存在于缓存中,则标记尚未到达一个问题)。
为了防止/绕过OutOfMemoryException,我尝试了三种不同的方法,虽然它们有效但我并不喜欢它们中的任何一种。
首先我尝试在调用GC.Collect();
之前做了一个通用的Graphics.FromImage(image)
,但是我不喜欢强制收集,因为它会对性能产生重大影响。
我的第二种方法是在catch语句中调用GC.Collect()
,然后递归调用TagAsProductImage(image)
,但如果GC无法释放足够的内存,这可能会导致无限循环。
最后我最终得到了上面的代码,我不能说我也不喜欢。
自从从服务中获取图像的整个操作后,我可能会使用GC.Collect()
- >保存 - >标记是一个非常大的标记,所以收集的性能很小,但我真的想要一个更好的解决方案。
如果有人对此有明智的解决方案,请分享。
答案 0 :(得分:17)
如果您正在寻找一种方法来确保您有足够的内存可用于某项操作,请使用MemoryFailPoint
。
通过using
,您可以定义一个需要一定内存量的区域。如果没有,它将抛出可恢复的InsufficientMemoryException
。
有关详细信息,请参阅http://msdn.microsoft.com/en-us/library/system.runtime.memoryfailpoint.aspx。
答案 1 :(得分:10)
这里遇到了不同的问题,此代码使用非常的小内存。可悲的是,GDI +异常非常糟糕。使用TaskMgr.exe,进程选项卡进行诊断。查看+选择列并勾选GDI对象,句柄和用户对象。
如果我的怀疑是正确的,那么当代码运行时,您将看到GDI Objects计数器让您的进程不断攀升。当它达到10,000时,Windows决定代码存在根本性的错误,并拒绝再创建句柄。 GDI +然后对它有点g and并报告内存不足错误。错了,应该是'无法创建句柄'错误。它没有的错误代码。 .NET无法改善异常。
Anyhoo,原因是你没有在字体和画笔上调用Dispose()。使用使用语句包装它们。这通常不会造成麻烦,但是你的程序显然使用太少的垃圾收集内存来启动终结器线程。