Question

I am performing a set of operations against some images within a Silverlight OOB application however I am experiencing OutOfMemoryExceptions when performing these operations against multiple larger images. The images themselves are around 15mb JPEG files, which individually use up around 100mb memory when loaded into a BitmapImage.

I am processing these images one by one, however the BitmapImage itself isn't being cleaned up between images. When processing 10 images the memory usage (as shown in Task Manager) grows to over a gig in size before collapsing back to 100mb once the process is complete.

I've distilled the issue down to an in browser test application which simply loads the image data into a BitmapImage object, and consists of the following code:

    private void ButtonBase_OnClick(object sender, RoutedEventArgs e)
    {
        byte[] imageData = LoadImageData();

        for (int i = 0; i < 10; i++)
        {
            BitmapImage bitmapImage = new BitmapImage();
            using (MemoryStream memoryStream = new MemoryStream(imageData))
            {
                bitmapImage.SetSource(memoryStream);
            }

            GC.Collect();
        }
    }

    private byte[] LoadImageData()
    {
        using (var stream = Assembly.GetExecutingAssembly().GetManifestResourceStream("ImageLoadingMemoryIssue.largeimage.jpg"))
        {
            byte[] buffer = new byte[stream.Length];
            stream.Read(buffer, 0, buffer.Length);
            return buffer;
        }
    }

How do I force the BitmapImage to be cleaned up between each iteration within the loop to prevent memory issues when processing multiple files?

Thanks

Was it helpful?

Solution 2

I managed to resolve this by waiting for the ImageOpened/Failed events before continuing on and loading and processing the next image. For some reason this allows the memory to be cleared up at that point rather than waiting for all images to be loaded.

    private static async Task<BitmapImage> LoadBitmapImageAsync(byte[] imageData)
    {
        BitmapImage bi = new BitmapImage();

        TaskCompletionSource<object> taskCompletionSource = new TaskCompletionSource<object>();

        EventHandler<RoutedEventArgs> openedHandler = (s2, e2) => taskCompletionSource.TrySetResult(null);
        EventHandler<ExceptionRoutedEventArgs> failedHandler = (s2, e2) => taskCompletionSource.TrySetResult(null);

        bi.ImageOpened += openedHandler;
        bi.ImageFailed += failedHandler;

        using (MemoryStream memoryStream = new MemoryStream(imageData))
        {
            bi.SetSource(memoryStream);
        }

        await taskCompletionSource.Task;

        bi.ImageOpened -= openedHandler;
        bi.ImageFailed -= failedHandler;
        return bi;
    }

OTHER TIPS

    for (int i = 0; i < 10; i++)
    {
        BitmapImage bitmapImage = new BitmapImage();
        using (MemoryStream memoryStream = new MemoryStream(imageData))
        {
            bitmapImage.SetSource(memoryStream);
        }
        // release reference underlying byte array
        // see: http://code.logos.com/blog/2008/04/memory_leak_with_bitmapimage_and_memorystream.html
        bitmapImage.SetSource(null);
        GC.Collect();
    }
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top