Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
302 views
in Technique[技术] by (71.8m points)

c# - Preventing OutOfMemoryException with GC.AddMemoryPressure()?

I'm currently debugging a method we use to tag images with a certain text before displaying them in our system.

The tag method looks like this at the moment:

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;
}

To put things in context: This method is being called after an image has been retrieved from our image server and saved to a local cache (that our system shares with other systems that needs the same pictures).

We've been having problems with OutOfMemoryExceptions when reaching using (Graphics... (when the image needs to be retrieved from the server prior to tagging, if the image exists in the cache the tagging hasn't been a problem).

To prevent/circumvent the OutOfMemoryException I've tried three different approaches, and while they work I don't really like any of them.

First I tried doing a generic GC.Collect(); before calling Graphics.FromImage(image) which worked (of course) but I don't like forcing Collects since it leaves a big hit on performance.

My second approach was to call GC.Collect() in the catch-statement and then recursively calling TagAsProductImage(image) but this is might lead to a infinite loop if GC fails to free up enough memory.

And finally I ended up with the above code, which I can't say I'm to fond of either.

I can probably get away with using GC.Collect() since the whole operation of getting the image from the service -> saving -> tagging is quite a big one so the performance hit from the collect will be minimal but I'd really like a better solution.

If anyone have a smart solution to this, please share.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

If you are looking for a way to ensure you'll have enough memory available for an operation, use MemoryFailPoint.

With this, through a using, you can define a region in which you will need a certain amount of memory. If that isn't available, it will throw a recoverable InsufficientMemoryException.

See http://msdn.microsoft.com/en-us/library/system.runtime.memoryfailpoint.aspx for more information.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...