For some days I have been trying to optimize an image processing program (cropping, rotate, changing brightness and undo) written in c# 4.0. Getting suggestions from google I have optimized the code in many ways. At first some disposable objects hadn’t been disposed that’s why exception was shown. But I have tried to dispose all disposable objects. Still the program is showing out of memory exceptions. That’s why I have uploaded the program for better solutions. Please download from the link

http://www.box.com/s/8eab0f3669ec4d79e3fc

My machine configuration: Core 2 Duo, 2 GB RAM, Windows XP service pack 3

Follow the steps:

Run the program

Load multiple images (at least 6) (each image is 3.5 MB or greater)

Double click on an image, crop (right click) and save. Do the same operation for other images. See what happens. It will show out of memory exceptions.

If any other operations (e.g. changing brightness) is done repeatedly (again and again) then it also shows out of memory exception.

I am eagerly waiting for your reply.

class ImageProcessingHandler
  {
    CurrentImageHandler objCurrImageHandler;

    int brightnessValue = 0;

    public ImageProcessingHandler(Bitmap currBmp)
    {
        objCurrImageHandler = new CurrentImageHandler();

        if (objCurrImageHandler.CurrentBitmap != null)
        {
            objCurrImageHandler.CurrentBitmap.Dispose();
            objCurrImageHandler.CurrentBitmap = null;
        }

        objCurrImageHandler.CurrentBitmap = new Bitmap(currBmp);
    }

    public Bitmap rotateImage()
    {
        try
        {
            objCurrImageHandler.CurrentRotationHandler.Flip(RotateFlipType.Rotate90FlipNone);

        }
        catch (Exception ex)
        {
            //MessageBox.Show("Error occured: " + ex.Message, "Image Processing", MessageBoxButtons.OK, MessageBoxIcon.Error);
        }
        return objCurrImageHandler.CurrentBitmap;
    }


    public Bitmap cropImageCustom(Rectangle cropArea)
    {
        objCurrImageHandler.RestorePrevious();

        using (Bitmap bmpImage = new Bitmap(objCurrImageHandler.CurrentBitmap))
        {

            Bitmap bmpCrop = bmpImage.Clone(cropArea, bmpImage.PixelFormat);
            objCurrImageHandler.CurrentBitmap.Dispose();
            objCurrImageHandler.CurrentBitmap = new Bitmap(bmpCrop);
            bmpCrop.Dispose();
        }

        return objCurrImageHandler.CurrentBitmap;

    }

    public Bitmap increaseBrightness()
    {

        brightnessValue = 10;
        objCurrImageHandler.CurrentBrightnessHandler.SetBrightness(brightnessValue);

        return objCurrImageHandler.CurrentBitmap;
    }


    public Bitmap undoImage()
    {

        objCurrImageHandler.ResetBitmap();
        return objCurrImageHandler.CurrentBitmap;
    }

    public void saveImage()
    {

        string fileName = ""; // "CommonInformation.TEMP_IMAGE_PATH + CommonInformation.selectedPageNumber.ToString() + ".jpg"";

        if (File.Exists(fileName))
        {
            File.Delete(fileName);
        }

        objCurrImageHandler.CurrentBitmap.Save(fileName, ImageFormat.Jpeg);
        objCurrImageHandler.CurrentBitmap.Dispose();

    }
 }

public class CurrentImageHandler
  { 
    ImageHandler imageHandler;
    public CurrentImageHandler(ImageHandler imageHandler)
    {
        this.imageHandler = imageHandler;
    }

    public void Flip(RotateFlipType rotateFlipType)
    {
        imageHandler.RestorePrevious();
        this.imageHandler.CurrentBitmap.RotateFlip(rotateFlipType);

    }

    public void SetBrightness(int brightness)
    {
        imageHandler.RestorePrevious();
        if (brightness < -255) brightness = -255;
        if (brightness > 255) brightness = 255;
        ColorMatrix cMatrix = new ColorMatrix(CurrentColorMatrix.Array);
        cMatrix.Matrix40 = cMatrix.Matrix41 = cMatrix.Matrix42 = brightness / 255.0F;
        imageHandler.ProcessBitmap(cMatrix);
    }

}

public class ImageHandler
  {
    private Bitmap _currentBitmap;
    private Bitmap _bitmapbeforeProcessing;

    public Bitmap CurrentBitmap
    {
        get
        {
            if (_currentBitmap == null)
            {
                _currentBitmap = new Bitmap(1, 1);
            }
            return _currentBitmap;
        }
        set { _currentBitmap = value; }
    }

    public string CurrentBitmapPath { get; set; }

    public void ResetBitmap()
    {
        if (_currentBitmap != null && _bitmapbeforeProcessing != null)
        {
            using (Bitmap temp = (Bitmap)_currentBitmap.Clone())
            {
                this.CurrentBitmap.Dispose();
                this.CurrentBitmap = (Bitmap)_bitmapbeforeProcessing.Clone();
                _bitmapbeforeProcessing = (Bitmap)temp.Clone();

            }

        }
    }

    internal void RestorePrevious()
    {
        if (_bitmapbeforeProcessing != null)
        {
            _bitmapbeforeProcessing.Dispose();
            _bitmapbeforeProcessing = null;
        }
        _bitmapbeforeProcessing = new Bitmap(_currentBitmap);
    }

    internal void ProcessBitmap(ColorMatrix colorMatrix)
    {
        using (Bitmap bmap = new Bitmap(_currentBitmap.Width, _currentBitmap.Height))
        {
            using (ImageAttributes imgAttributes = new ImageAttributes())
            {
                imgAttributes.SetColorMatrix(colorMatrix);
                using (Graphics g = Graphics.FromImage(bmap))
                {
                    g.InterpolationMode = InterpolationMode.NearestNeighbor;
                    g.DrawImage(_currentBitmap, new Rectangle(0, 0, _currentBitmap.Width, _currentBitmap.Height), 0, 0, _currentBitmap.Width, _currentBitmap.Height, GraphicsUnit.Pixel, imgAttributes);
                }
            }

            if (_currentBitmap != null)
                _currentBitmap.Dispose();

            _currentBitmap = (Bitmap)bmap.Clone();
        }

    }
}

Dani AI

Generated

As suggested and confirmed, the root cause is memory use from full‑resolution bitmaps. A 5100 x 6540 image expands in memory to roughly

bytes = width height (bitsPerPixel / 8)

so at 24bpp: 510065403 ~= 100,062,000 bytes (~95.5 MB). At 32bpp it is ~133,416,000 bytes (~127.3 MB). Six images therefore occupy on the order of 570–760 MB just for raw bitmaps, not counting the temporary clones your code creates during processing. On a 32‑bit process/XP machine with 2 GB RAM that easily triggers OutOfMemoryException.

Concrete, high‑impact changes (applied to the posted methods like ResetBitmap and ProcessBitmap):

  • Stop making multiple temporary clones. Replace triple Clone/Clone usage with a simple reference swap when a true copy is not required:
var temp = _currentBitmap;
_currentBitmap = _bitmapbeforeProcessing;
_bitmapbeforeProcessing = temp;
  • Avoid cloning a rendered bitmap. Create the new bitmap, draw into it, dispose the old bitmap, then assign the new one (do not wrap the new bitmap in a using block if you keep it):
Bitmap bmap = new Bitmap(w, h);
using (Graphics g = Graphics.FromImage(bmap)) { ... }
_currentBitmap.Dispose();
_currentBitmap = bmap;
  • Only keep thumbnails in memory for the UI. Keep file paths and load full resolution on demand (edit/save). Limit undo depth or persist undo images to disk instead of memory if full‑size history is needed.

As a last resort (not a design fix) force finalizers to free GDI+ handles:

GC.Collect();
GC.WaitForPendingFinalizers();
GC.Collect();

These changes remove many large, short‑lived allocations and will greatly reduce OOM occurrences on a 32‑bit/low‑RAM system.

Recommended Answers

All 2 Replies

If these are the only objects here and there's no recursive functions in there, your problem is that the bitmaps are too big. There's simply no place for hidden references to stick around. (These images: are they 3.5 MB compressed, before they're loaded? Or are they 3.5 MB as bitmaps?)

You might be able to make your program survive by forcing a garbage collection at certain times.

These images: are they 3.5 MB compressed, before they're loaded? Or are they 3.5 MB as bitmaps?)

They are 3.5 MB as JPEG. resolution is 5100 x 6540

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.