内存未在WPF映像中发布

时间:2014-02-19 10:09:33

标签: c# wpf image canvas memory-leaks

我正在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。

任何人都可以帮我解决这个问题吗?

2 个答案:

答案 0 :(得分:9)

首先,您应该通过显式调用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;

答案 1 :(得分:2)

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

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

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

请注意,这是自动流程,您不应该(并且您不希望)负责内存管理。

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