WinRT示例持有的内存未发布

时间:2015-04-28 05:09:46

标签: c# image memory memory-leaks windows-runtime

我正在尝试从样本中删除图像时释放图像所占用的内存。我附上sample来说明这个问题。

重现此问题的步骤:

步骤1:运行样本,您将注意到样本将消耗大约21 MB的样本

步骤2:点击AddCtrl按钮,将消耗约54 mb

步骤3:点击RemoveCtrl按钮,消耗的内存不会被释放。

我在微软的论坛上发布了这个,他们说这是操作系统的问题。有人可以指出我可用的任何解决方法来释放被占用的内存。

1 个答案:

答案 0 :(得分:0)

.NET中的垃圾收集通常不会在不再引用对象时立即释放内存,但在您的情况下还有更多内容。在示例中,您的代码通过将图像添加到StackPanel来添加图像,但是删除按钮会尝试通过从其父网格中删除ScrollViewer(它是StackPanel的父级)来清除它们。这是原始代码:

private void btnRemoveControl_Click(object sender, RoutedEventArgs e)
{
    parentGrid.Children.Remove(scrollViewer);
}

我认为这是一种奇怪的方法,所以我更改了代码,只是从StackPanel中删除了添加它们的图像:

private void btnRemoveControl_Click(object sender, RoutedEventArgs e)
{
    stackPanel.Children.Clear();
}

这实际上导致在单击“删除”按钮后立即释放大部分内存。在我的测试中,单击“添加”会将内存增加到50 MB,并使用此新代码单击“删除”将使其减少到29 MB。

但请记住,除非承受压力,否则.NET不会过于积极地回收内存。所以,我添加了另一行:

private void btnRemoveControl_Click(object sender, RoutedEventArgs e)
{
    stackPanel.Children.Clear();
    GC.Collect();
}

使用该代码,单击“删除”会在我的测试中将内存从50 MB降至12 MB。

然而,将GC.Collect()调用放入代码中通常是一个非常糟糕的主意,并且对于性能来说非常糟糕,因为它会迫使所有代的GC直接运行。最好让.NET在认为需要时清理内存。我只添加了该行来证明GC是否可以在需要时释放剩余的内存。

你需要做的是确保你没有持有你不再需要的对象的引用,这样.NET可以在它到达时清理内存。在您的原始代码中,我相信ScrollViewer仍在某处被引用,可能是因为它是在XAML中定义的。 ScrollViewer保存对StackPanel的引用,StackPanel保存对图像的引用,因此它们都不能被垃圾收集。但是,如果您只是删除图像,这就是您真正试图从内存中解放出来的图像,那就可以了。