我正在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。
任何人都可以帮我解决这个问题吗?
答案 0 :(得分:9)
首先,您应该通过显式调用GC.Collect()
来收集内存并查看内存是否发布,因为GC集合是不确定的。在方法执行GC运行并回收内存后,您无法确定。
所以,最后把这段代码显式强制GC运行以检查实际内存是否被释放:
GC.Collect();
GC.WaitForPendingFinalizers();
GC.Collect();
但是,BitmapImage
创建中存在一些已知的内存泄漏问题,您可以参考here,here和here。
实际上,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时间的操作。