C# 如何在Silverlight中强制清理BitmapImage

C# 如何在Silverlight中强制清理BitmapImage,c#,silverlight,C#,Silverlight,我正在对Silverlight OOB应用程序中的一些图像执行一组操作,但是在对多个较大的图像执行这些操作时,我遇到OutOfMemoryException。这些图像本身是大约15mb的JPEG文件,当加载到BitmapImage中时,它们各自会占用大约100mb的内存 我正在一个接一个地处理这些图像,但是位图图像本身并没有在图像之间被清理。当处理10个图像时,内存使用量(如任务管理器中所示)会增长到超过1千兆字节,然后在处理完成后会收缩回100mb 我将问题归结为一个浏览器内测试应用程序,该应

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

我正在一个接一个地处理这些图像,但是位图图像本身并没有在图像之间被清理。当处理10个图像时,内存使用量(如任务管理器中所示)会增长到超过1千兆字节,然后在处理完成后会收缩回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;
        }
    }
private void按钮base\u OnClick(对象发送方,路由目标)
{
字节[]imageData=LoadImageData();
对于(int i=0;i<10;i++)
{
BitmapImage BitmapImage=新的BitmapImage();
使用(MemoryStream MemoryStream=新的MemoryStream(imageData))
{
bitmapImage.SetSource(memoryStream);
}
GC.Collect();
}
}
专用字节[]LoadImageData()
{
使用(var stream=Assembly.getExecutionGassembly().GetManifestResourceStream(“ImageLoadingMemorySue.largeimage.jpg”))
{
byte[]buffer=新字节[stream.Length];
stream.Read(buffer,0,buffer.Length);
返回缓冲区;
}
}
如何在循环中的每次迭代之间强制清理
位图图像
,以防止处理多个文件时出现内存问题

感谢(inti=0;i<10;i++) { BitmapImage BitmapImage=新的BitmapImage(); 使用(MemoryStream MemoryStream=新的MemoryStream(imageData)) { bitmapImage.SetSource(memoryStream); } //释放引用底层字节数组 //见:http://code.logos.com/blog/2008/04/memory_leak_with_bitmapimage_and_memorystream.html bitmapImage.SetSource(空); GC.Collect(); }
我通过等待ImageOpen/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;
    }
专用静态异步任务LoadBitmapImageAsync(字节[]imageData)
{
BitmapImage bi=新的BitmapImage();
TaskCompletionSource TaskCompletionSource=新的TaskCompletionSource();
EventHandler openedHandler=(s2,e2)=>taskCompletionSource.TrySetResult(null);
EventHandler failedHandler=(s2,e2)=>taskCompletionSource.TrySetResult(null);
bi.ImageOpened+=openedHandler;
bi.ImageFailed+=failedHandler;
使用(MemoryStream MemoryStream=新的MemoryStream(imageData))
{
bi.SetSource(内存流);
}
等待taskCompletionSource.Task;
bi.ImageOpened-=openedHandler;
bi.ImageFailed-=failedHandler;
返回bi;
}

您是否尝试过保留一个全局变量并设置其源代码?这没有什么区别,内存使用没有得到清理。我还尝试将源设置为一个小图像,以强制它清理-这里有一些东西没有正确清理。一旦退出循环,它最终会消失,因此它不是传统意义上的内存泄漏。如果是这种情况,您是否尝试将for循环的内容放入方法中?我对Silverlight了解不多,但是你能用类似的东西来分析你的应用程序吗?这是我以前尝试过的事情之一,除了
SetSource(null)
抛出异常之外,它不会导致释放内存使用,虽然我现在已经找到了一种方法来实现它,但我也尝试了链接文章中提到的包流方法。我认为这篇文章更多的是关于WPF的,因为我没有看到所描述的内存问题。
    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;
    }