【发布时间】:2010-08-23 22:13:12
【问题描述】:
我正在使用 .NET4 WPF DataGrid 来显示一个包含大量图像的 SQL 表。
有问题的 XAML 代码是:
...
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<Image Source="{Binding Converter={StaticResource ImageConverter}, Path=Picture}" Stretch="Uniform" MaxHeight="200" />
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
...
ImageConverter 是这样写的:
[ValueConversion(typeof(Binary), typeof(BitmapImage))]
public class ImageConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if (value != null)
{
BitmapImage bi = new BitmapImage();
bi.BeginInit();
bi.StreamSource = new System.IO.MemoryStream((value as Binary).ToArray());
bi.EndInit();
if (bi.CanFreeze) bi.Freeze();
return bi;
}
else return null;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
我的问题是上面的代码会不会泄露内存?
我已尝试对此进行一些分析,但我不确定我是否正确解释了结果。
首先,包含图像的 SQL 表使用 38MB 的磁盘空间(图像应以 png 格式存储)。通过 LINQ 将所有图像加载到数据网格后,该应用程序使用了大约 170+ MB 的额外 RAM。这可能有助于解压缩图像以及 wpf 数据网格即使在启用虚拟化时也是一个巨大的内存消耗这一事实。关闭窗口后,内存使用量不会下降。重新打开窗口会导致另外 170+ MB 的 RAM 被使用,使总内存使用量大约为 400MB。如果我再次重新打开窗口,那么内存使用量将下降到大约 330MB。再次重新打开窗口会使内存使用量达到 380MB。再次重新打开使其达到 270MB。再次重新打开使其达到 426MB。所以你可以看到非常波动......
这一点测试是在 Win7 x64 和 8GB RAM 下完成的(应用程序是使用 Any CPU 选项编译的)。
我确实在具有
我对这些结果的解释是,除非内存子系统上存在高压,否则 GC 不会费心清理。但是在那种情况下,在我关闭窗口后调用 GC.Collect() 应该释放大部分内存吗?只是我没有,当我调用 GC.Collect 时,我只看到内存使用量下降了 4-6MB(我还尝试了所有可能的参数,包括在所有代上强制收集和调用 GC.WaitForPendingFinalizers())。
这让我想到可能是未使用的泄漏数据被推送到页面文件中。但是页面文件使用量会根据内存使用量下降和上升。
这里考虑的所有事情都不应该是内存泄漏,但是在我关闭窗口后我无法降低内存使用量。我确实尝试将一些 .NET 分析器附加到我的进程中,但是这些分析器非常复杂,以至于我无法确定显示的图像对象是否仍然存在并被某些东西引用。还是它们已经死了,而 GC 根本没有清理它们...
【问题讨论】: