【问题标题】:Releasing BitmapImages used as Image control Source (memory problem)释放用作Image control Source的BitmapImages(内存问题)
【发布时间】:2011-04-03 15:53:01
【问题描述】:

我有一个简单的 WPF 窗口,它下面有一个 Image 控件和一个 Slider 控件。当用户移动滑块时,我正在加载各种图像并将其设置为图像控件的源。我得到了很多图像,大小不等,最大为 200 KB,但是当我将滑块向后和第四次移动时,程序开始占用大量内存。数百和数百兆的内存。其中大部分最终都会被垃圾收集,但不是全部。

也许 WPF 不是要走的路,还是我应该强制使用 G/C?我尝试将图像加载为位图并使用Imaging.CreateBitmapSourceFromHBitmap() 和 Win32-api 获取位图源以删除和处置等等,但我只是让事情变得更糟:)

我想我应该在加载和分配新的图像源之前尝试获取现有图像源并以某种方式释放它。

有什么想法吗?

编辑

我正在添加一些运行良好的示例代码,并且似乎可以保持内存低而正常:

    private Image _lastImage;

    // Event when user moves the slider control, load image using the filname in
    // the _images[] array which contains hundreds of images
    private void SliderChanged(object sender, RoutedPropertyChangedEventArgs<double> e)
    {
        if (_lastImage != null)
            _lastImage.Dispose();

        var image = Image.FromFile(_images[(int)ImageSlider.Value]);
        Snapshot.Source = ImageToBitmapImage(image);

        _lastImage = image;
    }

    private static ImageSource ImageToBitmapImage(Image image)
    {
        BitmapImage bitmapImage;
        using (var ms = new MemoryStream())
        {
            image.Save(ms, ImageFormat.Jpeg);
            bitmapImage = new BitmapImage();
            bitmapImage.BeginInit();
            bitmapImage.StreamSource = new MemoryStream(ms.ToArray());
            bitmapImage.EndInit();
        }
        return bitmapImage;
    }

【问题讨论】:

    标签: wpf


    【解决方案1】:

    强制 GC 收集确实很可怕。而是调用Bitmap 对象的.Dispose() 方法,这就是它的用途!

    【讨论】:

    • 我试过了,但没有用。我很确定我以某种方式错误地加载和分配源:(
    • 我在从文件创建位图源的方式上稍微更改了我的代码,并确保我处理了之前的位图,正如你所说的(正如我之前尝试过但失败了)。瞧,它现在可以工作了。将使用示例代码更新原始问题。
    • @Jonah,如果 Snapshot.Source 不为空,您可以将其转换为 Image,然后在分配新图像之前将其处理掉。如果您没有对图像进行如此多的引用,那么 GC 一开始就可以自己完成,而不会产生额外的复杂性。
    【解决方案2】:
    1. 您使用的方法 (Imaging.CreateBitmapSourceFromHBitmap()) 是非托管的,可能需要您手动对其进行 .Dispose()。
    2. WPF 允许您通过给定的 URI 加载位图:请参阅http://msdn.microsoft.com/en-us/library/system.windows.media.imaging.bitmapimage.aspx
    3. GC 将负责收集您拥有的所有托管对象(例如使用 BitmapImage)。
    4. 您可能正在将太多图像加载到内存中。源图像非常快地积累内存(32 位颜色的 1024x786 图像占用大约 3mb 的内存)。 GC 必须非常努力地清理它们。您可以在加载后减小图像的大小(按比例缩小)并使用更少的内存
    5. 最后,GC 不保证在 GC 周期后会释放所有内存。 它承诺“尽最大努力”。虽然通常调用 GC.Collect(0);将强制执行完整的 GC 周期并释放几乎所有可以释放的内容。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2014-03-19
      • 2011-02-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多