首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >用GC.AddMemoryPressure()阻止OutOfMemoryException?

用GC.AddMemoryPressure()阻止OutOfMemoryException?
EN

Stack Overflow用户
提问于 2010-11-11 21:03:06
回答 1查看 7.2K关注 0票数 16

我目前正在调试一种方法,我们使用该方法在系统中显示图像之前使用特定的文本标记图像。

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

代码语言:javascript
复制
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(),因为从服务获取图像的整个操作->保存->标签是一个相当大的操作,所以收集对性能的影响将是最小的,但我真的想要一个更好的解决方案。

EN

回答 1

Stack Overflow用户

发布于 2010-11-11 21:37:21

你在这里有一个不同的问题,这段代码只占用很少的内存。遗憾的是,GDI+异常相当糟糕。使用TaskMgr.exe的Processes选项卡诊断此问题。查看+选择列并勾选GDI对象、句柄和用户对象。

如果我的怀疑是正确的,您将看到GDI对象计数器在此代码运行时不断攀升。当它达到10,000时,Windows会判定代码存在根本性的错误,并拒绝创建更多的句柄。然后,GDI+对此有点笨拙,并报告了内存不足错误。错误,应该是“无法创建句柄”错误。一个它没有的错误代码。.NET对改进异常无能为力。

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

票数 10
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/4154648

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档