内存未在 WPF 图像中释放

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/21877221/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-13 10:55:06  来源:igfitidea点击:

Memory not getting released in WPF Image

c#wpfimagecanvasmemory-leaks

提问by Uthistran Selvaraj.

I am loading and unloading images in Canvas. I used the below code to load the Image.

我正在加载和卸载Canvas. 我使用以下代码加载Image.

Before loading my Imagethe memory consumption is 14.8MB.

在加载之前我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

The Imagedisplayed correctly and the memory consumption now is 20.8MB. Then I unloaded the Imageby the below code:

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();

The Imagegets removed after this, but the memory is still 20.8 MB.

Image这之后被删除,但仍然记忆是20.8 MB。

Can anyone help me out this?

谁能帮我解决这个问题?

回答by Rohit Vats

First of all you should test by explicitly invoking GC.Collect()to collect memory and see that memory releases or not because GC collection is indeterministic. You can't be sure that after your method execution GC runs and reclaim the memory.

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

So , at end put this code to explicitly force GC to run to check if actually memory is released or not:

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

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


However, there is some known memory leak issues in BitmapImagecreation which you can refer here, hereand here.

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

Actually under the covers WPF keeps a strong reference between the static BitmapImage and the Image and hook some events on Bitmap image. So, you should freeze the bitmapImage before assigning to image. WPF doesn't hook events on freezed bitmapImage. Also set CacheOption to avoid any caching memory leak of bitmapImage.

实际上,WPF 在静态 BitmapImage 和 Image 之间保持强引用,并在 Bitmap 图像上挂钩一些事件。因此,您应该在分配给 image 之前冻结 bitmapImage。WPF 不会在冻结的位图图像上挂钩事件。还要设置 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;

回答by ken2k

In .Net there is something called the garbage collector(GC) that is in charge of managing the memory you're using.

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

  • When you create an instance of an object, it requires some more memory.
  • When you remove your ImageSourcefrom the Childrencollection, you don't actually free any memory, you just say "I don't want to use this instance anymore".
  • 创建对象的实例时,它需要更多内存。
  • 当你ImageSourceChildren集合中移除你的时候,你实际上并没有释放任何内存,你只是说“我不想再使用这个实例了”。

At this point the GC will help you. It'll automatically detect instances that are not used anymore, and will free the associated memory for you.

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

Do note it's an automatic processand you shouldn't (and you don't want to) take care of the memory management.

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

You can call GC.Collect();to force the garbage collector to do its job right now, you'll see the memory will be released. NOTE:GC.Collect();should be used in debug to detect memory leaks, but 99% of times you shouldn't call it explicitly in production code. GC.Collect();is an operation that can use a lot of CPU time.

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