如何在Silverlight中强制清理BitmapImage

时间:2014-04-09 16:13:54

标签: c# silverlight

我正在对Silverlight OOB应用程序中的某些图像执行一组操作,但是在针对多个较大图像执行这些操作时遇到OutOfMemoryExceptions。图像本身大约是15mb的JPEG文件,当加载到BitmapImage中时,它们单独使用大约100mb的内存。

我正在逐个处理这些图像,但是BitmapImage本身并没有在图像之间进行清理。处理10个图像时,内存使用量(如任务管理器中所示)增长到一个大小的gig,然后在完成该过程后折回到100mb。

我已将问题提炼到浏览器测试应用程序中,该应用程序只是将图像数据加载到BitmapImage对象中,并包含以下代码:

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

如何在循环内的每次迭代之间强制清除BitmapImage以防止在处理多个文件时出现内存问题?

由于

2 个答案:

答案 0 :(得分:0)

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

答案 1 :(得分:0)

我设法通过等待ImageOpened / Failed事件来解决这个问题,然后继续并加载和处理下一个图像。由于某种原因,这允许在那时清除内存,而不是等待加载所有图像。

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