Понимание утечек памяти - PullRequest
       15

Понимание утечек памяти

0 голосов
/ 07 января 2019

Я пытаюсь понять утечки памяти WPF, и после прочтения этой темы у меня есть некоторые неясные области.

Вопросы лучше всего получать из примера, поэтому давайте определим:

Модель:

public class Mom : INotifyPropertyChanged
{
   public ObservableCollection<Kid> Kids { get; set; }

   private string name;
   public string Name
   {
       get => name;
       set => Set(ref name, value);
   }

   public event PropertyChangedEventHandler PropertyChanged;

   protected void Set<T>(ref T field, T newValue = default(T), [CallerMemberName] string propertyName = null)
   {
       field = newValue;
       PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
   }
}

ViewModel (DataContext) может выглядеть так:

public class MomViewModel, INotifyPropertyChanged
{
   private Mom selected;
   public Mom Selected
   {
       get => selected;
       set => Set(ref selected, value);
   }
}

Теперь я хочу задать вопросы об этих 2 сценариях связывания в XAML:

Первая привязка:

<ListView ItemsSource="{Binding Selected.Kids}">
...
</ListView >

Вторая привязка:

<TextBlock Text="{Binding Selected.Kids.Count}" />

Теперь представьте, что внутри ViewModel у нас есть таймер, который назначает новую маму каждую секунду. Это Selected = new Mom { .. };.

1: Будет ли привязка 1 производить утечку памяти? Свойство имеет тип ObservableCollection, которое реализует INotifyPropertyChanged, но само свойство этого не делает (просто обычное get, set).

2: Будет ли связывание 2 производить утечку памяти? Привязка напрямую относится к Count из коллекции и не реализует INotifyPropertyChanged.

Обратите внимание, что само представление (XML) никогда не уничтожается - только свойство Selected изменяется каждую секунду. Мне (также) не ясно, когда WPF разрешает сборку мусора - только когда представление уничтожено или когда изменяется привязка. Мои тесты здесь неубедительны ...

Спасибо.

Ответы [ 2 ]

0 голосов
/ 07 января 2019

Ни одна из имеющихся у вас частей WPF не вызовет утечек памяти.

Привязки WPF являются слабыми ссылками, поэтому они по сути своей не поддерживают жизнь. Существует вероятность утечки памяти, если вы свяжетесь с poco, который не реализует inotifypropertychanged. Вы избежали этого. Поднимаете ли вы свойство, измененное в сеттере или нет, не имеет значения Следовательно, подсчет также не вызывает утечки памяти.

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

Если вы хотите разобраться с тем, что не позволяет собирать мусор в сложном корпоративном приложении, вы можете попробовать Redgate Ants profiler. Есть бесплатная пробная версия.

0 голосов
/ 07 января 2019

В следующем примере кода предыдущий экземпляр Mom будет иметь право на сборку мусора после того, как вы установили свойство Selected source для нового объекта Mom независимо от того, привязаны ли вы к Selected.Kids или Selected.Kids.Count * * 1006

public sealed class MomViewModel : INotifyPropertyChanged, IDisposable
{
    private readonly System.Timers.Timer _timer = new System.Timers.Timer();

    public MomViewModel()
    {
        _timer.Interval = 2000;
        _timer.Elapsed += (s, e) => Selected = new Mom();
        _timer.Start();
    }

    private Mom selected;
    public Mom Selected
    {
        get => selected;
        set => Set(ref selected, value);
    }

    public event PropertyChangedEventHandler PropertyChanged;

    private void Set<T>(ref T field, T newValue = default(T), [CallerMemberName] string propertyName = null)
    {
        field = newValue;
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }

    public void Dispose()
    {
        _timer.Dispose();
    }
}

Вы не вносите никаких утечек памяти, устанавливая следующие привязки в представлении:

<ListView ItemsSource="{Binding Selected.Kids}" />
<TextBlock Text="{Binding Selected.Kids.Count}" />
...