關於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)); }
我們把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/