0

I'm working on a software in C# used to manipulate images. I have a lot of images (more than 11000) and when I execute my program after a few minutes, I have an "OutOfMemoryException"

There is my code :

private void GenerateImages()
{
    try
    {
        Parallel.ForEach(listImagesStart, startImg =>
        {
            bool docontinue = true;
            try
            {
                startImg.LoadImage(_baseFileResults);
            }
            catch
            {
                docontinue = false;
            }
            if (docontinue)
            {
                //Save image as file
                startImg.Save();

                // Do rotate
                MyImg lastRotate = baseImg;
                MyImg imgtmp;
                String[] tabRotate = new String[3] { "_90", "_180", "_270"};
                foreach (String rotate in tabRotate)
                {
                    imgtmp = new GenImg(baseImg.FileName + rotate + baseImg.FileExtension);
                    imgtmp.LoadImage(lastRotate);
                    imgtmp.Rotate90();
                    imgtmp.Save();
                    lastRotate = imgtmp;
                }

                startImg.Dispose();
                imgtmp.Dispose();
            }
        });
    }
    catch (Exception e)
    {
        MessageBox.Show(e.Message, "Error", MessageBoxButton.OK, MessageBoxImage.Error);
#if DEBUG
        MessageBox.Show(e.StackTrace, "Error", MessageBoxButton.OK, MessageBoxImage.Error);
#endif
    }
}

And MyImg :

class myImg
{
    public Byte[] Matrix;
    public int Height;
    public int Width;

    public void LoadImage(String filePath)
    {
        // create new Matrix/Heigth/Width from file
    }

    public void LoadImage(myImg img)
    {
        Matrix = new Byte[img.Matrix.Length];
        Array.Copy(img.Matrix, Matrix, img.Matrix.Length);
        Height = img.Height;
        Width = img.Width;
    }

    public void Rotate90()
    {
        // Save before
        int tmpWidth = Height;
        int tmpHeight = Width;
        Byte[] tmpMatrix = new Byte[Matrix.Length];

        for (int r = 0; r < tmpHeight; r++)
        {
            for (int c = 0; c < tmpWidth; c++)
            {
                int prevR = Height - c - 1;
                int prevC = r;
                tmpMatrix[c + r * tmpWidth] = Matrix[prevC + prevR * Width];
            }
        }

        // Copy new image
        Array.Copy(tmpMatrix, Matrix, Matrix.Length);
        Width = tmpWidth;
        Height = tmpHeight;
    }

    public void Dispose()
    {
        SavePath = null;
        Matrix = null;
        Points = null;
        Width = 0;
        Height = 0;
        GC.Collect();
    }
}

The SystemOutOfMemoryException occurs at instructionnew Byte[Length]. I think it's I create too many array but I don't know what to do.

2
  • In your foreach loop you call imgtmp.LoadImage as well as Rotate90 both alllocate the memory. Is this the loop where you are processing 11000 images? In addition you dont mention how large each image is.Your don't call dispose until after you leave this loop. And this foreach loop is within a parallel for. You should rethink how you call your Dispose. Commented Feb 13, 2017 at 14:48
  • @DaveS I'm processing my 11000 images in the Parallel.Foreach, the list is listImagesStart. Images are 700x700 pixels. I modified my code to call Dispose if docontinue is false. (I'm waiting for results) Commented Feb 13, 2017 at 15:06

1 Answer 1

1

The main issue is that listImagesStart keeps reference of each startImg item. This will keep GC from freeing memory allocated by myImg.LoadImage (with the array Matrix).

A quick solution : you can set Matrix to null to recycle the memory.

public void UnLoadImage()
{
      Matrix = null ; // this will allow GC to recycle memory used by Matrix
}

then (I removed the useless docontinue variable) :

try
{
    startImg.LoadImage(_baseFileResults);

    //Save image as file
    startImg.Save();

    // Do rotate
    MyImg lastRotate = baseImg;
    MyImg imgtmp;
    String[] tabRotate = new String[3] { "_90", "_180", "_270"};
    foreach (String rotate in tabRotate)
    {
        imgtmp = new GenImg(baseImg.FileName + rotate + baseImg.FileExtension);
        imgtmp.LoadImage(lastRotate);
        imgtmp.Rotate90();
        imgtmp.Save();
        lastRotate = imgtmp;
    }

    startImg.Dispose();
    imgtmp.Dispose();
}
catch
{

}
finally
{
      startImg.Unload(); // Here is the trick
}
Sign up to request clarification or add additional context in comments.

2 Comments

Is there possible to call my Dispose instead of UnLoadImage ? My Dispose do the Matrix = null
You are free to rename UnloadImage to Dispose() and implements IDisposable

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.