Следующие XAML-возможности могут утечь память? - PullRequest
4 голосов
/ 24 августа 2010

Я использую .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, содержащая изображения, использует 38 МБдисковое пространство (изображения должны храниться в формате png).После загрузки всех изображений в сетку данных через LINQ приложение использует около 170 МБ дополнительной оперативной памяти.Это, вероятно, может способствовать распаковке образов и тому факту, что сетка данных wpf является гигантским захватом памяти даже при включенной виртуализации.После закрытия окна использование памяти не падает.Повторное открытие окна приводит к использованию еще 170+ МБ ОЗУ, что делает общее использование памяти примерно 400 МБ.Если я снова открою окно, то использование памяти упадет до 330 МБ.Повторное открытие окна снова увеличивает объем используемой памяти до 380 МБ.Повторное открытие снова принимает его до 270 МБ.Повторное открытие снова приводит к 426 МБ.Так что, как вы можете видеть, очень нестабильно ...

Это небольшое тестирование было проведено с Win7 x64 и 8 ГБ оперативной памяти (приложение скомпилировано с опцией Любой процессор).

Я сделалПопробуйте тот же тест на виртуальной машине XP с <512 МБ оперативной памяти (около 384, если я правильно помню).И каждый раз, когда я снова открывал окно, я сначала видел резкое падение использования памяти, когда окно загружалось, а затем то же самое количество памяти использовалось повторно, поэтому общее использование было примерно одинаковым. </p>

Я интерпретирую эти результаты такчто ГХ не будет заниматься очисткой, если только подсистема памяти не будет сильно нагружена.Но в этом случае вызов GC.Collect () после закрытия окна должен освободить большую часть памяти?Единственное, что я не сделал, я увидел только снижение использования памяти на 4-6 МБ, когда я вызвал GC.Collect (я также попробовал все возможные параметры, включая принудительный сбор во всех поколениях и вызов GC.WaitForPendingFinalizers ()).

Это заставило меня задуматься о том, что, возможно, неиспользуемые утечки данных помещаются в файл подкачки.Но использование файла подкачки уменьшается и увеличивается в соответствии с использованием памяти равным образом.

Все вещи, которые здесь рассматриваются, не должны быть здесь утечкой памяти, но я не могу заставить использование памяти снижаться после того, как я закрылсяокно.Я пытался подключить к своему процессу какой-то профилировщик .NET, но эти профилировщики настолько сложны, что я не могу понять, живы ли показанные объекты изображений и на них ссылаются.Или они мертвы, и ГК просто не очистила их ...

Ответы [ 3 ]

4 голосов
/ 21 октября 2010

Способ определения, записана ли память в файл подкачки, - GC.GetTotalMemory(true).Это должно возвращать фактическое потребление памяти процессом .NET, включая любые страницы, которые могли быть записаны в файл подкачки.

Это может даже отличаться от, например, памяти, сообщаемой диспетчером задач, но будет сообщатьчто фактически было выделено объектами .NET.

См. http://social.msdn.microsoft.com/Forums/en-US/csharpgeneral/thread/2ebbff38-f881-47ad-a4b4-9c9157fb3b5b для получения дополнительной информации о разнице в потреблении памяти, сообщаемой диспетчером задач, и GetTotalMemory.

Мои предположенияGC.GetTotalMemory(true) сообщит, что фактически вся память была освобождена после сбора.

1 голос
/ 20 октября 2010

По моему мнению, в этом коде нет утечки памяти.Тот факт, что на виртуальной машине память почти сразу падает, означает, что GC выполняет свою работу правильно.

Одна вещь, которую я нашел полезным в подобной ситуации, - это поместить куда-нибудь кнопку, которая вызывает GC.Collect, и нажатьэто несколько раз.Обычно через ~ 3 раза мертвые объекты становятся "GCollected", если это не тот случай, у вас, вероятно, есть утечка.

0 голосов
/ 22 октября 2013

проблема утечки памяти с DataGridTemplateColumn, похоже, исчезла с .NET 4.5

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...