分类目录

链接

2012 年 12 月
 12
3456789
10111213141516
17181920212223
24252627282930
31  

近期文章

热门标签

新人福利,免费薅羊毛

现在位置:    首页 > .NET > 正文
wpf内存泄漏问题及解决方案
.NET 暂无评论 阅读(3,984)

Windows Presentation Foundation即WPF,它代表着Windows平台UI的未来。微软有其自身的打算,而稍晚于WPFSilverlight将占领Web和移动 设备市场。不过,和任何的新技术一样,都会经历一些问题,如某些相当严重的内存泄漏问题。

我们要讨论诸多内存泄漏。第一个问题已经发现一段时间,但它并没有引起大多程序员的关注,甚至是专家们的注意。引发该问题需要以下条件配合:

  1. 引用对象X属性P的数据绑定路径
  2. 对象X含直接引用或间接引用数据绑定操作的目标对象

属性P通过PropertyDescriptor对象而非DependencyProperty对象或PropertyInfo对象访问

这个问题在KB 938416中有详细的描述。

接下来是一个让人极其厌烦的Bug,它在我们使用一个数据绑定集合代替另外一个时触发。Ayende Rahien有引发该问题的源代码。Mike Brown解释道:

经过深入研究以后,我发现该绑定系统并没有解除对“Name”属性的监听程序,但相关数据已被修改。

这 很明显是一个Bug,它和绑定系统有关。当你注意到数据被修改过,而非解除已有绑定(这次假设Name绑定Textblock)并再次使用该元素,就像重 新创建元素集那样。不幸的是,Textblock从来没有解除该绑定。现在如果让数据变成可观测的集合(必要情况下把匿名类型转换为标准的类)并让该集合 触发CollectionChanged事件(例如:Data[0]=Data[0]),一切运行正常。

以下的内存泄漏来自于jgoldb的微软博客上:

  • 如果初始HWND在XP上被撤销就会导致CMilChannel泄漏
  • 使用绑定的每条线程会导致ShutdownListener泄漏
  • 在XP的HW中创建和消除WriteableBitmap
  • SW Viewport 3D w/ VisualBrush和WB等,都会在XP上引起泄漏问题

除了这些泄漏以外,他还列出了一些其他的常见开发错误导致的内存泄漏,以及一些已修复的WPF问题。

wpf内存泄漏问题解决方案

1、   如果用MVVM模式,View里面有图片,ViewModel里面有View引用,要把ViewModel里面的View设置为空,View里面的DataContext设置为空,不然有可能导致内存泄漏

清除引用:

this.Page.DataContext = null;

this.Page = null;

2、   类与类之间尽量不要互相引用,如果相互引用了要手动设置里面的引用为空,不然 会导致内存泄漏

Class1 class1 =new Class1();

Class2 class2 = new Class2();

class1.Class2 = class2;

class2.Class1 = class1;

清除引用:

class2.Class1 = null;

class2 = null;

class1.Class2 = null;

class1 =null;

3、   自定义控件里面有ImageBitMapSource属性值之类或者引用类属性时,要手动删除并设置为空

CustomControl cc = new CustomControl();

BitMapSource bms = new BitMapSource();

bms.UriSource = ……;

cc.Image = new Image(){Source= bms };

清除引用:

cc.Image=null;

bms =null;

4、   MVVM模式里面继承INotifyPropertyChangedViewModel里面的命令(CommandManager.RegisterClassCommandBinding)有可能导致内存泄漏

protected ICommand CreateCommand(Action<ExecutedRoutedEventArgs> executed, Action<CanExecuteRoutedEventArgs> canExecute)

              {

            var rCommand = new RoutedCommand();

            var cBinding = new CommandBinding(rCommand);

            CommandManager.RegisterClassCommandBinding(typeof(UIElement), cBinding);

            cBinding.CanExecute += (s, e) =>

            {

                if (canExecute != null)

                    canExecute(e);

                else

                    e.CanExecute = true;

            };

            cBinding.Executed += (s, e) =>

            {

                executed(e);

            };

                     return rCommand;

               }

修改成:

protected ICommand CreateCommand(Action<object> execute)

        {

            return new RelayCommand(execute);

        }

public class RelayCommand : Icommand

{

        ………….

}

5、   页面关闭时没结束的线程要结束线程

6、   页面关闭时静态变量要设置为空

7、   使用事件时,如果是一个类的事件在另一个类里面被注册(委托方法在这个类里面),要注销事件

Window1.w2.TextBox1.TextChanged += new TextChangedEventHandler(this.TextBox1_TextChanged);

Window1.w2.TextBox1.TextChanged -= new TextChangedEventHandler(this.TextBox1_TextChanged); 事件
8、                   用静态事件时要注销事件
9、                   在Image里面使用BitMapImage时要用

BitmapImage bi = new BitmapImage();

bi.BeginInit();

                bi.CacheOption = BitmapCacheOption.OnLoad;

                bi.UriSource = new Uri(path);

                bi.EndInit();

                bi.Freeze();

10、        调用垃圾回收

GC.Collect();
   GC.WaitForPendingFinalizers();
   GC.Collect();
11、               如果绑定的数据源没有实现INotifyPropertyChanged,可能导致内存泄漏
 WPF 中,不标记为 OneTime 必须侦听属性的一个数据绑定操作从源对象 (对象 X 更改通知。WPF  INotifyPropertyChanged 界面使用 DependencyProperties 类的内置通知。如果 DependencyProperties 类和 INotifyPropertyChanged 接口都不可用,WPF 使用 ValueChanged 事件。 此行为涉及到与属性 P 相对应的 PropertyDescriptor 对象上调用 PropertyDescriptor.AddValueChanged 方法。 遗憾的是,此操作会导致公共语言运行库 (CLR) 可以创建从此 PropertyDescriptor 对象 X 的强引用。 CLR 还保留全局表中的 PropertyDescriptor 对象的引用
public class CustomCollectionClass : INotifyPropertyChanged

 

============ 欢迎各位老板打赏~ ===========

本文版权归Bruce's Blog所有,转载引用请完整注明以下信息:
本文作者:Bruce
本文地址:wpf内存泄漏问题及解决方案 | Bruce's Blog

发表评论

留言无头像?