简体   繁体   中英

Understanding memory leaks

I'm trying to understand WPF memory leaks and after reading up on the subject, I have some unclear areas.

Questions are best derived from example, so let's define:

Model:

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));
   }
}

The ViewModel (DataContext) could look like this:

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

Now I want to ask questions about these 2 binding scenarios in XAML:

First binding:

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

Second binding:

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

Now imagine that inside the ViewModel, we have a timer that assigns a new Mom every second. That is Selected = new Mom { .. }; .

Q1: Would binding 1 produce a memory leak? The property is of type ObservableCollection which implements INotifyPropertyChanged, but the property itself does not (just regular get,set).

Q2: Would binding 2 produce a memory leak? The binding is directly against Count which is from Collection and doesn't implement INotifyPropertyChanged.

Notice that the view (XML) itself is never destroyed - only the "Selected" property is changed every second. It is (also) not clear to me when WPF allows for garbage collection - only when the view is destroyed, or whenever a binding changes. My tests are inconclusive here...

Thanks.

In the following sample code, the previous instance of Mom will be eligible for garbage collection after you have set the Selected source property to a new Mom object regardless of whether you bind to Selected.Kids or Selected.Kids.Count :

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();
    }
}

You don't introduce any memory leaks by setting up the following bindings in the view:

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

None of the WPF specific parts you have there will cause memory leaks.

WPF bindings are weak references so they do not inherently keep things alive. There is the potential for a memory leak if you bind to a poco which does not implement inotifypropertychanged. You avoided that. Whether you raise property changed in a setter or not does not matter. Hence count also doesn't cause any memory leak.

If you have a problem anywhere it looks much more likely to be in how you are retaining a reference to each of these Mom you're newing up every second. Something still has a reference to these and is not allowing it to go out of scope. A fix might be as simple as taking older Mom's out the observablecollection and disposing them.

If you wanted to get to grips with exactly what is keeping things from being garbage collected in a complex enterprise sized app then you could give redgate Ants profiler a try. There's a free trial.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM