绑定到列表会导致内存泄漏

use*_*735 5 c# memory wpf binding memory-leaks

当我将ListBox的ItemsSource绑定到List时,绑定引擎在控件消失后保持列表元素.这会导致所有列表元素保留在内存中.使用ObservalbleCollection时问题就消失了.为什么会这样?

窗口标记内的xaml

<Grid>
    <StackPanel>
        <ContentControl Name="ContentControl">
            <ListBox ItemsSource="{Binding List, Mode=TwoWay}" DisplayMemberPath="Name"/>
        </ContentControl>
        <Button Click="Button_Click">GC</Button>
    </StackPanel>
</Grid>
Run Code Online (Sandbox Code Playgroud)

代码背后:

public MainWindow()
    {
        InitializeComponent();
        DataContext = new ViewModel();
    }

private void Button_Click(object sender, RoutedEventArgs e)
    {
        this.DataContext = null;
        ContentControl.Content = null;
        GC.Collect();
        GC.WaitForPendingFinalizers();
    }
Run Code Online (Sandbox Code Playgroud)

视图模型

class ViewModel : INotifyPropertyChanged
{
    //Implementation of INotifyPropertyChanged ...

    //Introducing ObservableCollection as type resolves the problem
    private IEnumerable<Person> _list = 
            new List<Person> { new Person { Name = "one" }, new Person { Name = "two" } };

    public IEnumerable<Person> List
    {
        get { return _list; }
        set
        {
            _list = value;
            RaisePropertyChanged("List");
        }
    }

class Person
{
    public string Name { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

编辑:为了检查人员泄漏,我使用了ANTS和.Net内存分析器.两者都显示在按下GC按钮后,只有绑定引擎保持对person对象的引用.

dev*_*hog 6

啊,你找到了 现在我明白你的意思了.

您将内容设置为null,因此您杀死强制ListBox但仍然将ItemsSource绑定到List,因此ListBox内存未完全释放.

遗憾的是,这是一个众所周知的问题,并且在MSDN上也有很好的记录.

如果您没有绑定到DependencyProperty或实现INotifyPropertyChanged或ObservableCollection的对象,则绑定可能会泄漏内存,并且您必须在完成后取消绑定.

这是因为如果对象不是DependencyProperty或者没有实现INotifyPropertyChanged或者没有实现INotifyCollectionChanged(Normal list没有实现它),那么它通过PropertyDescriptors AddValueChanged方法使用ValueChanged事件.这会导致CLR从PropertyDescriptor到对象创建强引用,并且在大多数情况下,CLR将在全局表中保留对PropertyDescriptor的引用.

因为绑定必须继续监听更改.当目标保持使用时,此行为使PropertyDescriptor和对象之间的引用保持活动状态.这可能导致对象中的内存泄漏以及对象引用的任何对象.

问题是......是实施INotifyPropertyChanged的人吗?