代码之家  ›  专栏  ›  技术社区  ›  Marko

以下XAML是否有可能泄漏内存?

  •  4
  • Marko  · 技术社区  · 14 年前

    所讨论的XAML代码是:

    ...
    <DataGridTemplateColumn.CellTemplate>
       <DataTemplate>
          <Image Source="{Binding Converter={StaticResource ImageConverter}, Path=Picture}" Stretch="Uniform" MaxHeight="200" />
       </DataTemplate>
    </DataGridTemplateColumn.CellTemplate>
    ...
    

    图像转换器是这样写的:

    [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将所有图像加载到datagrid之后,应用程序使用了大约170+MB的额外RAM。这可能有助于解压图像,而且即使启用了虚拟化,wpf数据网格也是一个巨大的内存占用者。关闭窗口后,内存使用率不会下降。重新打开该窗口将使用另外170+MB的RAM,使总内存使用量约为400MB。如果我再次打开窗口,那么内存使用量将下降到330MB左右。再次打开窗口将占用380MB的内存。重新打开需要270MB。重新打开需要426MB。所以你可以看到非常波动。。。

    这个小测试是用win7x64和8gbram完成的(应用程序是用任意CPU选项编译的)。

    我确实在一台内存为512MB的虚拟xp机器上进行了相同的测试(如果我没记错的话,大约是384)。每次我重新打开窗口时,我首先看到加载窗口时内存使用量急剧下降,然后重复使用相同数量的内存,因此总体使用量大致相同。

    我对这些结果的解释是,除非内存子系统上有高压,否则GC不会费心清理。但如果是那样的话GC.收集()关闭窗口后是否应释放大部分内存?但我没有,我打电话时只看到内存使用量下降了4-6MBGC.收集(我还尝试了所有可能的参数,包括对所有代强制收集和调用GC.等待终结器()).

    这让我想到,可能是未使用的泄漏数据被推到页面文件。但是页面文件的使用量随着内存使用量的增加而下降。

    考虑到所有的事情,这里不应该有内存泄漏,但是我关上窗户后,内存的使用率就降不下来了。我确实尝试将一些.NET探查器附加到我的进程中,但是这些探查器太复杂了,以至于我无法确定所显示的图像对象是否仍然存在并被某些对象引用。或者他们死了而GC根本没有清理他们。。。

    3 回复  |  直到 14 年前
        1
  •  4
  •   Pieter van Ginkel    14 年前

    找出内存是否写入页面文件的方法是通过 GC.GetTotalMemory(true) . 这应该返回.NET进程的实际内存消耗,包括可能已写入页文件的任何页。

    这甚至可能与任务管理器报告的内存不同,但它将报告.NET对象实际分配的内存。

    http://social.msdn.microsoft.com/Forums/en-US/csharpgeneral/thread/2ebbff38-f881-47ad-a4b4-9c9157fb3b5b 有关任务管理器和 GetTotalMemory .

    我猜是这样的 将报告在收集之后所有内存实际上已被释放。

        2
  •  1
  •   Francesco De Vittori    14 年前

    在我看来,没有内存泄漏的代码。虚拟机上的内存几乎立即下降这一事实意味着GC正在正确地执行其工作。

    在类似的情况下,我发现有一件事很有用,那就是把一个按钮放在某个可以呼叫的地方GC.收集,打了几下。通常在~3次“收集”死物后,如果不是这样,则可能发生泄漏。

        3
  •  0
  •   blindmeis    11 年前