2

dotMemory告诉我(下面的屏幕截图,“WPF 绑定泄漏”)绑定到字典时存在内存泄漏,如下所示:

<ComboBox ItemsSource="{Binding Items, Mode=OneTime}"
          DisplayMemberPath="Value"
          SelectedValue="{Binding SelectedItem}"
          SelectedValuePath="Key" />

问题1,给大家:为什么是内存泄漏(即我应该使用什么场景来遇到问题)以及如何解决它?


问题 2,dotMemory 专家:为什么这么基本的 mvvm 应用程序(见下文)报告了这么多问题?我应该解决这些问题吗?如何?


MCVE(创建新的 WPF 解决方案,在 xaml 中使用上述代码)代码后面:

public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();
        DataContext = new ViewModel();
    }
}

public class ViewModel : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;
    public void OnPropertyChanged([CallerMemberName] string property = "") =>
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(property));

    public Dictionary<string, string> Items { get; } = new Dictionary<string, string>
    {
        { "1", "One" },
        { "1a", "One and a" },
        { "2a", "Two and a" },
    };

    string _selectedItem = "1a";
    public string SelectedItem
    {
        get { return _selectedItem; }
        set
        {
            _selectedItem = value;
            OnPropertyChanged();
        }
    }
}
4

2 回答 2

3

绑定未实现 INotifyPropertyChanged 接口或不使用 OneTime 绑定模式的目标对象

答案 1: Xaml 绑定到 Dictionary,它是 KeyValuePair 的集合,并且它的 Value 属性被指定为DisplayMemberPath. 公开的 KeyValuePair 没有实现 INotifyPropertyChanged 接口,也无法OneTimeDisplayMemberPath. 因此,字典的所有项目将永远留在内存中。

答案 2: dotMemory 报告潜在问题,只有您可以确定它是否是真正的问题。不幸的是,.NET 本身会重复字符串并创建永远不会填充数据的数组,dotMemory 也会报告它们,因为无法区分这些对象是由“用户”还是由系统创建的。我建议你看看为什么你有最终确定的对象,似乎你忘记为某些对象调用 IDisposable.Dispose 方法。并检查这些未填充的数组是否由您创建。

于 2018-01-25T13:11:24.890 回答
1

你得到内存泄漏的原因是你绑定到一个没有实现接口 INotifyPropertyChanged 的​​对象。

当我们绑定到字典的 Value 属性时...

绑定目标开始侦听属性更改通知。如果属性不是DependencyProperty或实现 INotifyPropertyChanged的​​对象,则 WPF 将求助于订阅System.ComponentModel.PropertyDescriptor类的ValueChanged事件以在源对象的属性值更改时获取通知。

为什么这是个问题?好吧,由于运行时创建了一个对此 PropertyDescriptor 的引用,而后者又引用了我们的源对象,并且运行时永远不会知道何时释放该初始引用(除非明确告知),因此 PropertyDescriptor 和我们的源对象都将保留在记忆。

来源

这可以通过绑定到ObservableDictionary<Key, Value>来解决

于 2020-01-03T09:58:22.490 回答