【问题标题】:How to force cleanup of BitmapImage in Silverlight如何在 Silverlight 中强制清理 BitmapImage
【发布时间】:2014-04-15 17:39:02
【问题描述】:

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

我正在一张一张地处理这些图像,但是 BitmapImage 本身并没有在图像之间被清理。处理 10 个图像时,内存使用量(如任务管理器中所示)会增长到超过 1 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,以防止处理多个文件时出现内存问题?

谢谢

【问题讨论】:

  • 您是否尝试过保留全局变量并设置其来源?
  • 这没什么区别,内存使用没有得到清理。我还尝试将源设置为一个小图像以强制它清理 - 这里有些东西没有被正确清理。一旦你退出循环,它最终会消失,所以它不是传统意义上的内存泄漏。
  • 如果是这种情况,您是否尝试将 for 循环的内容放入方法中?我对 Silverlight 了解不多,但你能用 memprofiler.com 之类的东西来描述你的应用程序吗?

标签: c# silverlight


【解决方案1】:
    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();
    }

【讨论】:

  • 这是我之前尝试过的事情之一,除了 SetSource(null) 抛出异常之外,它不会导致内存使用量被释放,尽管我现在找到了一种导致它会发生
  • 我还尝试了链接文章中提到的 Wrapped stream 方法。我认为这篇文章更多地是关于 WPF,因为我没有看到所描述的内存问题。
【解决方案2】:

我设法通过等待 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;
    }

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2023-04-06
    • 2011-04-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-07-02
    相关资源
    最近更新 更多