简体   繁体   English

了解内存泄漏

[英]Understanding memory leaks

I'm trying to understand WPF memory leaks and after reading up on the subject, I have some unclear areas. 我试图了解WPF内存泄漏,并且在阅读了该主题之后,我有一些不清楚的地方。

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: ViewModel(DataContext)可能如下所示:

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: 现在,我想问有关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. 现在想象一下,在ViewModel中,我们有一个计时器,它每秒分配一个新的Mom。 That is Selected = new Mom { .. }; 那就是Selected = new Mom { .. }; .

Q1: Would binding 1 produce a memory leak? Q1:绑定1会产生内存泄漏吗? The property is of type ObservableCollection which implements INotifyPropertyChanged, but the property itself does not (just regular get,set). 该属性的类型为ObservableCollection,该类型实现INotifyPropertyChanged,但该属性本身不(仅常规获取,设置)。

Q2: Would binding 2 produce a memory leak? Q2:绑定2会产生内存泄漏吗? The binding is directly against Count which is from Collection and doesn't implement INotifyPropertyChanged. 该绑定直接针对来自Collection的Count ,并且不实现INotifyPropertyChanged。

Notice that the view (XML) itself is never destroyed - only the "Selected" property is changed every second. 请注意,视图(XML)本身从未被破坏-每秒仅更改一次“ Selected”属性。 It is (also) not clear to me when WPF allows for garbage collection - only when the view is destroyed, or whenever a binding changes. WPF允许进行垃圾回收(这也仅在视图被破坏或绑定发生更改时)对我来说还是不清楚的。 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 : 在以下示例代码中,在将Selected源属性设置为新的Mom对象之后,无论绑定到Selected.Kids还是Selected.Kids.CountMom的先前实例都可以进行垃圾回收:

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特定部件均不会导致内存泄漏。

WPF bindings are weak references so they do not inherently keep things alive. WPF绑定是弱引用,因此它们本质上不会保持活动。 There is the potential for a memory leak if you bind to a poco which does not implement inotifypropertychanged. 如果绑定到未实现inotifypropertychanged的poco,则可能会导致内存泄漏。 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. 因此,count也不会导致任何内存泄漏。

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. 如果您想确切地了解阻止复杂的企业级应用程序中垃圾收集的是什么,那么可以尝试一下redgate Ants profiler。 There's a free trial. 有免费试用版。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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