51

我是否需要在项目消失时取消绑定项目以防止内存泄漏?我想我只是有点担心,如果我重新加载并将新模板应用于控件,并且在该模板中存在与外部元素的绑定,是否会阻止为模板制作的控件被垃圾收集?

4

3 回答 3

80

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

这是因为如果对象不是 aDependencyProperty或未实现INotifyPropertyChanged,则它ValueChanged通过方法使用事件PropertyDescriptors AddValueChanged。这会导致 CLR 创建从PropertyDescriptor到的强引用,object并且在大多数情况下,CLR 会PropertyDescriptor在全局表中保留对 的引用。

因为绑定必须继续监听变化。由于目标仍在使用中,此行为使引用在 thePropertyDescriptor和 the之间保持活动状态。这可能会导致引用的对象和任何对象中object的内存泄漏,这包括数据绑定目标。objectobjectobject

所以简而言之,如果你绑定到一个DependencyPropertyINotifyPropertyChanged对象,那么你应该没问题,否则就像任何订阅的事件一样,你应该取消订阅你的绑定


编辑: 这有可能在 .NET4.5 中使用弱事件/引用进行了修复,但是经过几次快速测试后,对我来说似乎是一样的,我将不得不更深入地进行确认,所以我个人会说in可能会在 4.5 中修复 :)

于 2013-08-31T00:47:04.997 回答
13

不假装回答,仅供参考。在Finding Memory Leaks in WPF-based applications作者Jossef Goldberg的一篇经典文章中,详细描述了 WPF 应用程序中可能存在内存泄漏的情况。确实,大多数与 .NET 3.5/4.0 有关,但有些情况可能与今天有关。另外,有一个小的扩展名

关于泄漏的引用Binding

Cause:

kb 文章中记录了此泄漏。它被触发是因为:

TextBlock控件绑定到一个对象 (myGrid),该对象具有对TextBlock(它是 myGrid 子对象之一) 的引用。

Note:如kb 文章中所述,这种类型的 DataBinding 泄漏对于特定场景(而不是所有 DataBinding 场景)是唯一的。中的属性Path不是 aDependencyProperty并且不在实现的类上INotifyPropertyChanged,此外还必须存在强引用链。

代码:

myDataBinding = new Binding("Children.Count");
myDataBinding.Source = myGrid; 
myDataBinding.Mode = BindingMode.OneWay;
MyTextBlock.SetBinding(TextBlock.TextProperty, myDataBinding);

同样的泄漏代码也可以用 XAML 编写:

<TextBlock Name="MyTextBlock" 
           Text="{Binding ElementName=myGrid, Path=Children.Count}" />

Fix/Workaround:

方法很少,最简单的一种是在窗口即将关闭时清除绑定。

例如:

BindingOperations.ClearBinding(MyTextBlock, TextBlock.TextProperty);

另一种方法是将数据绑定的模式设置为 OneTime。有关其他想法,请参阅kb 文章

有用的链接:

使用 DataBinding 避免 WPF 内存泄漏

于 2013-08-31T08:05:42.960 回答
6

http://msdn.microsoft.com/en-us/library/aa970850.aspx,WPF使用弱事件模式,它不持有对对象的强引用,如果它们是对对象的唯一引用,则允许它们被 GC'ed一个东西。

“WPF 数据绑定的许多方面已经在如何实现事件中应用了弱事件模式。”

但是弱事件仅用于对象DependencyPropertiesINotifyPropertyChanged对象,因此如果您使用绑定模式绑定到 POCO,则OneTime可能会导致内存泄漏。

于 2013-08-30T23:47:46.427 回答