你的位置:首页 > ASP.net教程

[ASP.net教程]WPF 属性系统 依赖属性之内存占用分析


      关于WPF的属性系统园子内有不少这方面的文章。里面大都提到了WPF依赖属性的在内存方面的优化。但是里面大都一笔带过。那么WPF到底是怎么样节约内存的。我们通过WPF属性和普通的CLR属性对比来看一下WPF属性在节约内存方面的优势在哪里。

     普通的CLR属性

public partial class WindowMemory : Window{   Student0 stu;   public WindowMemory()  {    InitializeComponent();    List<Student0> list = new List<Student0>();    for (int i = 0; i < 10000000; i++)    {    stu = new Student0();    list.Add(stu);    }  }}

 public class Student0  {    public double Name { get; set; }    public double Name1 { get; set; }    public double Name2 { get; set; }    public double Name3 { get; set; }    public double Name4 { get; set; }    public double Name5 { get; set; }    public double Name6 { get; set; }    public double Name7 { get; set; }    public double Name8 { get; set; }    public double Name9 { get; set; }    public double Name10 { get; set; }  }

我们声明一个Student0类,里面放入十个属性。然后new 一千万个student 的实例加载到内存中。在任务管理器中看一下内存占用。

我们看到程序大概占用了一个G的内存。计算一下。因为c#中的属性是通过get set方法对一个私有字段的封装,也就是说这个类里面有十个double类型的私有字段。double类型占8个字节。一兆是1048576个字节,131072个double类型。一千万个double大概占用76兆的内存。我们这儿声明了十个也就是760兆。另外还有student对象占用的内存。所以这儿程序占用内存大概是一个G;

依赖属性

 public class Student0 : DependencyObject  {    public double Name    {      get      {        return (double)GetValue(NameProperty);      }      set      {        SetValue(NameProperty, value);      }    }    public double Name1    {      get      {        return (double)GetValue(Name1Property);      }      set      {        SetValue(Name1Property, value);      }    }    public double Name2    {      get      {        return (double)GetValue(Name2Property);      }      set      {        SetValue(Name2Property, value);      }    }    public double Name3    {      get      {        return (double)GetValue(Name3Property);      }      set      {        SetValue(Name3Property, value);      }    }    public double Name4    {      get      {        return (double)GetValue(Name4Property);      }      set      {        SetValue(Name4Property, value);      }    }    public double Name5    {      get      {        return (double)GetValue(Name5Property);      }      set      {        SetValue(Name5Property, value);      }    }    public double Name6    {      get      {        return (double)GetValue(Name6Property);      }      set      {        SetValue(Name6Property, value);      }    }    public double Name7    {      get      {        return (double)GetValue(Name7Property);      }      set      {        SetValue(Name7Property, value);      }    }    public double Name8    {      get      {        return (double)GetValue(Name8Property);      }      set      {        SetValue(Name8Property, value);      }    }    public double Name9    {      get      {        return (double)GetValue(Name9Property);      }      set      {        SetValue(Name9Property, value);      }    }    public double Name10    {      get      {        return (double)GetValue(Name10Property);      }      set      {        SetValue(Name10Property, value);      }    }public static readonly DependencyProperty NameProperty = DependencyProperty.Register("Name", typeof(double), typeof(Student0), new PropertyMetadata((double)55.55));    public static readonly DependencyProperty Name1Property = DependencyProperty.Register("Name1", typeof(double), typeof(Student0), new PropertyMetadata((double)55.55));    public static readonly DependencyProperty Name2Property = DependencyProperty.Register("Name2", typeof(double), typeof(Student0), new PropertyMetadata((double)55.55));    public static readonly DependencyProperty Name3Property = DependencyProperty.Register("Name3", typeof(double), typeof(Student0), new PropertyMetadata((double)55.55));    public static readonly DependencyProperty Name4Property = DependencyProperty.Register("Name4", typeof(double), typeof(Student0), new PropertyMetadata((double)55.55));    public static readonly DependencyProperty Name5Property = DependencyProperty.Register("Name5", typeof(double), typeof(Student0), new PropertyMetadata((double)55.55));    public static readonly DependencyProperty Name6Property = DependencyProperty.Register("Name6", typeof(double), typeof(Student0), new PropertyMetadata((double)55.55));    public static readonly DependencyProperty Name7Property = DependencyProperty.Register("Name7", typeof(double), typeof(Student0), new PropertyMetadata((double)55.55));    public static readonly DependencyProperty Name8Property = DependencyProperty.Register("Name8", typeof(double), typeof(Student0), new PropertyMetadata((double)55.55));    public static readonly DependencyProperty Name9Property = DependencyProperty.Register("Name9", typeof(double), typeof(Student0), new PropertyMetadata((double)55.55));    public static readonly DependencyProperty Name10Property = DependencyProperty.Register("Name10", typeof(double), typeof(Student0), new PropertyMetadata((double)55.55));  }

View Code

 

我们把student类修改为依赖对象,在里面实现十个依赖属性,此时来查看一下内存占用

此时只有三百多兆的内存占用。那么WPF的属性到底是如何节约内存的呢。因为CLR属性是在实例声明的时候就分配好了内存空间的。所以就算实例里面没有写入值,或者仍然是默认值,仍然会分配好内存空间。但是WPF的依赖属性不同。wpf的依赖属性是如下声明的

 public static readonly DependencyProperty NameProperty = DependencyProperty.Register("Name", typeof(double), typeof(Student0), new PropertyMetadata((double)55.55));

 

注意上面的这条语句才是依赖属性的声明。而类似下面这样的是我们通过clr属性对依赖属性NameProperty进行了包装,使我们访问起来更方便。就想普通的属性那样。
 public double Name{   get   {     return (double)GetValue(NameProperty);   }   set   {     SetValue(NameProperty, value);   }}

也就是说我们其实可以直接这样来声明Student0对象

 public class Student0 : DependencyObject  {    public static readonly DependencyProperty NameProperty = DependencyProperty.Register("Name", typeof(double), typeof(Student0), new PropertyMetadata((double)55.55));    public static readonly DependencyProperty Name1Property = DependencyProperty.Register("Name1", typeof(double), typeof(Student0), new PropertyMetadata((double)55.55));    public static readonly DependencyProperty Name2Property = DependencyProperty.Register("Name2", typeof(double), typeof(Student0), new PropertyMetadata((double)55.55));    public static readonly DependencyProperty Name3Property = DependencyProperty.Register("Name3", typeof(double), typeof(Student0), new PropertyMetadata((double)55.55));    public static readonly DependencyProperty Name4Property = DependencyProperty.Register("Name4", typeof(double), typeof(Student0), new PropertyMetadata((double)55.55));    public static readonly DependencyProperty Name5Property = DependencyProperty.Register("Name5", typeof(double), typeof(Student0), new PropertyMetadata((double)55.55));    public static readonly DependencyProperty Name6Property = DependencyProperty.Register("Name6", typeof(double), typeof(Student0), new PropertyMetadata((double)55.55));    public static readonly DependencyProperty Name7Property = DependencyProperty.Register("Name7", typeof(double), typeof(Student0), new PropertyMetadata((double)55.55));    public static readonly DependencyProperty Name8Property = DependencyProperty.Register("Name8", typeof(double), typeof(Student0), new PropertyMetadata((double)55.55));    public static readonly DependencyProperty Name9Property = DependencyProperty.Register("Name9", typeof(double), typeof(Student0), new PropertyMetadata((double)55.55));    public static readonly DependencyProperty Name10Property = DependencyProperty.Register("Name10", typeof(double), typeof(Student0), new PropertyMetadata((double)55.55));  }

然后通过setvalue,getvalue来存取值

注意其实依赖属性的声明,在这里或者用注册来形容更贴切,只是一个入口点。也就是我们平常常说的单例模式。属性的值其实都放在依赖对象的一个哈希表里面。这里资料很多,大家随便找下就可以找到。

所以依赖属性正在节约内存就在于这儿的依赖属性是一个static readonly 属性。所以不需要在对象每次实例化的时候都分配相关属性的内存空间,而是提供一个入口点。

知道了这些我们再看一个没什么实际意义的例子。将student0对象修改如下。

 public class Student0  {    public double Name { get { return 1.00; } set { Name = 1.00; } }    public double Name1 { get { return 1.00; } set { Name1 = 1.00; } }    public double Name2 { get { return 1.00; } set { Name2 = 1.00; } }    public double Name3 { get { return 1.00; } set { Name3 = 1.00; } }    public double Name4 { get { return 1.00; } set { Name4 = 1.00; } }    public double Name5 { get { return 1.00; } set { Name5 = 1.00; } }    public double Name6 { get { return 1.00; } set { Name6 = 1.00; } }    public double Name7 { get { return 1.00; } set { Name7 = 1.00; } }    public double Name8 { get { return 1.00; } set { Name8 = 1.00; } }    public double Name9 { get { return 1.00; } set { Name9 = 1.00; } }    public double Name10 { get { return 1.00; } set { Name10 = 1.00; } }  }

此时程序只占用了不到200兆内存。因为属性的本质其实就是一个get set 方法。而方法是不需要实例化的,只需要一个指针指向就可以了。这儿我没没有在属性get;set;这种简化写法下声明的私有字段。所以没有了这些私有字段占用的内存。内存占用大大减少。

仔细对比我们就会发现。wpf的属性系统真的没有特别设计来优化内存。只是这种提供入口点的方式顺带就减少了内存的占用。

 

本文地址:http://www.cnblogs.com/santian/p/4372667.html

博客地址:http://www.cnblogs.com/santian/

转载请以超链接形式标明文章原始出处。