【问题标题】:Memory not getting released in WPF ImageWPF Image 中未释放内存
【发布时间】:2014-03-19 14:10:35
【问题描述】:

我正在加载和卸载Canvas 中的图像。我使用下面的代码来加载Image

在加载我的Image 之前,内存消耗为 14.8MB。

Canvas c = new Canvas();

Image im = new Image();
ImageSource src = new BitmapImage(new Uri(@"E:Capture.png"));
im.Source = src;
im.Height = 800;
im.Width = 800;

c.Children.Add(im);
homegrid.Children.Add(c); //homegrid is my grid's name

Image 显示正确,现在内存消耗为 20.8MB。然后我通过以下代码卸载了Image

foreach (UIElement element in homegrid.Children)
{
    if (element is Canvas)
    {
        Canvas page = element as Canvas;

        if (page.Children.Count > 0)
        {
            for (int i = page.Children.Count - 1; i >= 0; i--)
            {
                if (page.Children[i] is Image)
                    (page.Children[i] as Image).Source = null;
                page.Children.RemoveAt(i);
            }
        }

        page.Children.Clear();
        page = null;
    }
}

homegrid.Children.RemoveAt(2);
InvalidateVisual();

Image 此后被删除,但内存仍为 20.8 MB。

谁能帮我解决这个问题?

【问题讨论】:

  • 如何收集垃圾?
  • 这不是内存泄漏。 GC 最终会处理那些不再被引用的实例。
  • @ken2k :我没明白你的意思。可以请教一下

标签: c# wpf image canvas memory-leaks


【解决方案1】:

在 .Net 中有一种叫做 垃圾收集器 (GC) 的东西,它负责管理您正在使用的内存。

  • 创建对象实例时,它需要更多内存。
  • 当您从 Children 集合中删除您的 ImageSource 时,您实际上并没有释放任何内存,您只是说“我不想再使用这个实例了”。

此时,GC 将为您提供帮助。它会自动检测不再使用的实例,并为您释放相关的内存。

请注意,这是一个自动过程,您不应该(也不想)处理内存管理。

您可以调用GC.Collect(); 强制垃圾收集器立即完成其工作,您会看到内存将被释放。 注意:GC.Collect(); 应在调试中用于检测内存泄漏,但 99% 的情况下您不应在生产代码中显式调用它GC.Collect(); 是一个会占用大量 CPU 时间的操作。

【讨论】:

  • 所以我使用图像并在我的工作完成后将 imageSource 设置为 null 并调用 GC.Collect() .. 但是内存不会清理.. 一段时间后我再次调用 GC .Collect() 然后它是干净的,否则它会保存内存 cheak 视频:- dropbox.com/s/c4ftl9lizqktw31/…
【解决方案2】:

首先,您应该通过显式调用 GC.Collect() 来收集内存并查看内存是否释放,因为 GC 收集是不确定的。您无法确定在您的方法执行后 GC 运行并回收内存。

所以,最后把这段代码显式地强制 GC 运行以检查是否实际内存被释放:

GC.Collect();
GC.WaitForPendingFinalizers();
GC.Collect();

但是,BitmapImage 创建过程中存在一些已知的内存泄漏问题,您可以参考hereherehere

实际上,WPF 在静态 BitmapImage 和 Image 之间保持强引用,并在 Bitmap 图像上挂钩一些事件。因此,您应该在分配给图像之前冻结 bitmapImage。 WPF 不会在冻结的 bitmapImage 上挂钩事件。还要设置 CacheOption 以避免 bitmapImage 的任何缓存内存泄漏。

Image im = new Image();    
BitmapImage bi = new BitmapImage();
bi.BeginInit();
bi.CacheOption = BitmapCacheOption.OnLoad;
bi.UriSource = new Uri(@"E:Capture.png");
bi.EndInit();
bi.Freeze();
ImageSource src = bi;
im.Source = src;
im.Height = 800;
im.Width = 800;

【讨论】:

    猜你喜欢
    • 2016-10-03
    • 2011-08-10
    • 1970-01-01
    • 2020-11-24
    • 1970-01-01
    • 2019-05-19
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多