【问题标题】:Binding to dictionary, memory leak is reported, how to fix?绑定字典,报内存泄漏,如何解决?
【发布时间】:2018-07-04 11:27:24
【问题描述】:

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

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

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


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

【问题讨论】:

  • 旁注,绑定到字典很糟糕,因为绑定不知道 jack 对字典的了解,所以它们将它们视为 IEnumerable>。因此,您会失去自动 DataTemplate 选择等 WPF 功能。使用实现 INotifyCollectionChanged 的​​ KeyedCollection 是一个更好的主意,因为它实现了 IEnumerable。另外,16b 也不用担心:/

标签: c# wpf mvvm memory-leaks dotmemory


【解决方案1】:

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

答案 1: Xaml 绑定到 Dictionary,它是 KeyValuePair 的集合,它的 Value 属性被指定为 DisplayMemberPath 的源。 暴露的 KeyValuePair 没有实现 INotifyPropertyChanged 接口,也无法为DisplayMemberPath 指定OneTime 绑定模式。所以, Dictionary 的所有条目都将永远留在内存中。

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

【讨论】:

  • 1. “字典的所有项目将永远留在内存中” - 你的意思是直到视图被卸载?我理解mechanics,我的问题是如何利用它(也就是做错什么让它爆炸)以及何时安全,或者说有没有安全的方法。
  • 2.我提供了一个 complete 代码,而我的问题是我为什么会看到这些。我提出了一些讽刺意味,问我该如何解决这些问题,因为它们不是我的。我可以忽略这些,但它们很吵,很难发现我自己的问题。例如。如果空白应用程序已经有 1000 个,我该如何找到自己的“稀疏数组”?
  • 永远直到视图被卸载我不记得了,需要检查。怎么办 - 绑定到不实现 INotifyPropertyChanged 类型的属性(使用除 OneTime 之外的任何绑定模式)如果您的“稀疏数组”将超过 4Kb(在这种情况下),您将看到它:)严重的是,我们将增加隐藏不需要的检查结果的可能性。尚无估算。
【解决方案2】:

您遇到内存泄漏的原因是您绑定到一个未实现接口 INotifyPropertyChanged 的​​对象。

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

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

为什么会出现这个问题?好吧,因为运行时创建了对 这个 PropertyDescriptor 又引用了我们的源对象, 并且运行时将永远不知道何时释放该初始值 参考(除非明确告知),PropertyDescriptor 都为 以及我们的源对象将保留在内存中。

(source)

通过绑定到 ObservableDictionary

解决了

【讨论】:

  • 什么是ObservableDictionary?而且我仍然不明白如何使内存泄漏。我在生产中使用了 wpf 应用程序,没有内存泄漏(它运行了好几天),并且与字典有很多绑定。
猜你喜欢
  • 2015-06-28
  • 1970-01-01
  • 1970-01-01
  • 2021-11-18
  • 2018-04-11
  • 2020-04-07
  • 1970-01-01
相关资源
最近更新 更多