Running multiple image manipulations in parallel causing OutOfMemory exception

Posted by Tom on Stack Overflow See other posts from Stack Overflow or by Tom
Published on 2012-06-08T14:48:01Z Indexed on 2012/06/08 16:40 UTC
Read the original article Hit count: 533

I am working on a site where I need to be able to split and image around 4000x6000 into 4 parts (amongst many other tasks) and I need this to be as quick as possible for multiple users.

My current code for doing this is

var bitmaps = new RenderTargetBitmap[elements.Length];

using (var stream = blobService.Stream(key))
{
    BitmapImage bi = new BitmapImage();
    bi.BeginInit();
    bi.StreamSource = stream;
    bi.EndInit();

    for (var i = 0; i < elements.Length; i++)
    {
        var element = elements[i];

        TransformGroup transformGroup = new TransformGroup();
        TranslateTransform translateTransform = new TranslateTransform();
        translateTransform.X = -element.Left;
        translateTransform.Y = -element.Top;
        transformGroup.Children.Add(translateTransform);

        DrawingVisual vis = new DrawingVisual();
        DrawingContext cont = vis.RenderOpen();
        cont.PushTransform(transformGroup);
        cont.DrawImage(bi, new Rect(new Size(bi.PixelWidth, bi.PixelHeight)));
        cont.Close();

        RenderTargetBitmap rtb = new RenderTargetBitmap(element.Width, element.Height, 96d, 96d, PixelFormats.Default);
        rtb.Render(vis);
        bitmaps[i] = rtb;
    }
}

for (var i = 0; i < bitmaps.Length; i++)
{
    using (MemoryStream ms = new MemoryStream())
    {
        PngBitmapEncoder encoder = new PngBitmapEncoder();
        encoder.Frames.Add(BitmapFrame.Create(bitmaps[i]));
        encoder.Save(ms);
        var regionKey = WebPath.Variant(key, elements[i].Id);
        saveBlobService.Save("image/png", regionKey, ms);
    }
}

I am running multiple threads which take jobs off a queue. I am finding that if this part of code is hit by 4 threads at once I get an OutOfMemory exception. I can stop this happening by wrapping all the code above in a lock(obj) but this isn't ideal. I have tried wrapping just the first using block (where the file is read from disk and split) but I still get the out of memory exceptions (this part of the code executes quite quickly).

  • I this normal considering the amount of memory this should be taking up?
  • Are there any optimisations I could make?
  • Can I increase the memory available?

UPDATE:

My new code as per Moozhe's help

public static void GenerateRegions(this IBlobService blobService, string key, Element[] elements)
{
    using (var stream = blobService.Stream(key))
    {
        foreach (var element in elements)
        {
            stream.Position = 0;
            BitmapImage bi = new BitmapImage();
            bi.BeginInit();
            bi.SourceRect = new Int32Rect(element.Left, element.Top, element.Width, element.Height);
            bi.StreamSource = stream;
            bi.EndInit();

            DrawingVisual vis = new DrawingVisual();
            DrawingContext cont = vis.RenderOpen();
            cont.DrawImage(bi, new Rect(new Size(element.Width, element.Height)));
            cont.Close();

            RenderTargetBitmap rtb = new RenderTargetBitmap(element.Width, element.Height, 96d, 96d, PixelFormats.Default);
            rtb.Render(vis);

            using (MemoryStream ms = new MemoryStream())
            {
                PngBitmapEncoder encoder = new PngBitmapEncoder();
                encoder.Frames.Add(BitmapFrame.Create(rtb));
                encoder.Save(ms);
                var regionKey = WebPath.Variant(key, element.Id);
                blobService.Save("image/png", regionKey, ms);
            }
        }
    }
}

© Stack Overflow or respective owner

Related posts about c#

Related posts about ASP.NET