我目前正在调试一种方法,我们使用该方法在系统中显示图像之前使用特定的文本标记图像。
标记方法目前看起来像这样:
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;
}
为了防止/绕过OutOfMemoryException,我尝试了三种不同的方法,虽然它们都有效,但我并不真正喜欢它们中的任何一种。
首先,在调用Graphics.FromImage(image)
之前,我尝试做一个通用的GC.Collect();
,这是可行的(当然),但我不喜欢强制收集,因为它会对性能造成很大的影响。
我的第二种方法是在catch语句中调用GC.Collect()
,然后递归地调用TagAsProductImage(image)
,但是如果GC无法释放足够的内存,这可能会导致无限循环。
最后,我最终得到了上面的代码,我不能说我喜欢上面的代码。
我也许可以使用GC.Collect()
,因为从服务获取图像的整个操作->保存->标签是一个相当大的操作,所以收集对性能的影响将是最小的,但我真的想要一个更好的解决方案。
发布于 2010-11-11 21:37:21
你在这里有一个不同的问题,这段代码只占用很少的内存。遗憾的是,GDI+异常相当糟糕。使用TaskMgr.exe的Processes选项卡诊断此问题。查看+选择列并勾选GDI对象、句柄和用户对象。
如果我的怀疑是正确的,您将看到GDI对象计数器在此代码运行时不断攀升。当它达到10,000时,Windows会判定代码存在根本性的错误,并拒绝创建更多的句柄。然后,GDI+对此有点笨拙,并报告了内存不足错误。错误,应该是“无法创建句柄”错误。一个它没有的错误代码。.NET对改进异常无能为力。
无论如何,原因是您没有在字体和画笔上调用Dispose()。用using语句将它们包装起来。这通常不会造成麻烦,但是您的程序显然使用了太少的垃圾回收内存来启动终结器线程。
https://stackoverflow.com/questions/4154648
复制相似问题