C# WPF映像中未释放内存

C# WPF映像中未释放内存,c#,wpf,image,canvas,memory-leaks,C#,Wpf,Image,Canvas,Memory Leaks,我正在画布中加载和卸载图像。我使用下面的代码加载图像 在加载我的图像之前内存消耗为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.A

我正在
画布中加载和卸载图像。我使用下面的代码加载
图像

在加载我的
图像之前
内存消耗为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
图像
显示正确,内存消耗现在为20.8MB。然后我用下面的代码卸载了
图像

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();
此后,
图像
将被删除,但内存仍为20.8MB


有人能帮我解决这个问题吗?

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

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

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


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

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

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

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


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

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

所以,在最后,将此代码显式地强制GC运行,以检查是否实际释放了内存:

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

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

实际上,WPF在静态位图图像和图像之间保持了一个强引用,并在位图图像上钩住了一些事件。因此,在分配给图像之前,您应该冻结位图图像。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;

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

所以,在最后,将此代码显式地强制GC运行,以检查是否实际释放了内存:

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

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

实际上,WPF在静态位图图像和图像之间保持了一个强引用,并在位图图像上钩住了一些事件。因此,在分配给图像之前,您应该冻结位图图像。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;

你怎么收集垃圾?那不是内存泄漏。GC最终会处理那些不再引用的实例。@ken2k:我不明白你的意思。你能告诉我你是怎么收集垃圾的吗?那不是内存泄漏。GC最终会处理那些不再引用的实例。@ken2k:我不明白你的意思。你能不能请ElLobrate这样我就可以使用图像了,在我的工作完成后,我将imageSource设置为null并调用GC.Collect()。。但记忆不会被清理。。过了一段时间,当我再次调用GC.Collect()时,它的clean else它的hold memory cheak video:-所以我使用图像,在我的工作完成后,我将imageSource设置为null并调用GC.Collect()。。但记忆不会被清理。。过了一段时间,当我再次调用GC.Collect()时,它的clean else将保留内存cheak视频:-