本篇借鑑了同事翔哥的勞動成果,在巨人的肩膀上把稿子又唸了一遍。網絡
內存泄漏的概念我這裏就不說了,以前《UWP開發入門(十三)——用Diagnostic Tool檢查內存泄漏》中提到過,即便有垃圾回收機制,寫C#仍是有可能發生內存泄漏。ide
通常來講,如下兩種狀況會致使內存泄漏:this
下面就UWP開發中具體的實例來講明須要避免的寫法spa
FakeService.Instance.ShowMeTheMoneyEvent += Instance_ShowMeTheMoneyEvent;
好比咱們有一個底層的FakeService,提供整個APP生命週期的數據和網絡的訪問。假設某個頁面+=了這個FackService的Event,在離開頁面時沒有-=掉。那麼該頁面就沒法被垃圾回收。code
合理的作法是在OnNavigatedFrom方法裏,把事件反註冊掉。對象
protected override void OnNavigatedFrom(NavigationEventArgs e) { base.OnNavigatedFrom(e); FakeService.Instance.ShowMeTheMoneyEvent -= Instance_ShowMeTheMoneyEvent; }
這種狀況就屬於對象內部的屬性未能被釋放,假設頁面內部存在Timer對象:blog
public sealed partial class TimerPage : Page { private DispatcherTimer Timer { get; set; } = new DispatcherTimer(); public ArrayList arrayList { get; set; } public TimerPage() { this.InitializeComponent(); arrayList = new ArrayList(10000000); Timer.Tick += Timer_Tick; Timer.Interval = TimeSpan.FromSeconds(1); Timer.Start(); } private void Timer_Tick(object sender, object e) { int count = 0; int.TryParse(TextBoxTimer.Text, out count); count += 1; TextBoxTimer.Text = count.ToString(); } private void Button_Click(object sender, RoutedEventArgs e) { this.Frame.GoBack(); } protected override void OnNavigatedFrom(NavigationEventArgs e) { base.OnNavigatedFrom(e); Timer.Stop(); } }
若是在離開頁面以前,未調用Timer對象的Stop方法,也未-=Tick事件(這裏Stop方法會自動-=Tick事件)。該頁面就不能正常的回收。繼承
這裏並非說全部的Event都須要在OnNavigatedFrom方法中-=,例如Control自己的Loaded、IsEnabledChanged等事件等並不會形成內存泄漏,反註冊這些事件是爲了不事件的重複觸發。而DispatcherTimer比較特殊,我理解它會把本身加到一個專門維護計時器的隊列中,而後不停的觸發Tick事件,若是沒有Stop或-=,就等於Timer一直引用了外部的對象,從而致使頁面自己也沒法回收。接口
這一條在不少的文檔上有所說起,很遺憾我無法經過Diagnostic Tools監測出來具體的泄漏,我猜想多是很小規模的內存泄漏。可是避免的方式很是容易,只要平時寫XAML注意一下就能夠了。生命週期
會出現問題的寫法是如下兩種:
其實很好處理。若是想監測變化,就老老實實繼承對應的接口。若是使用了普通的Property和集合,而且不想監測變化,必定記得Mode = OneTime。
固然若是屬性自己是dependency property,就不存在內存泄漏的狀況了。
<!--內存泄漏,由於Children集合沒有實現INotifyPropertyChanged來通知Count屬性變化--> <TextBlock Text="{Binding ElementName=layoutRoot, Path=Children.Count}" /> <!--不會內存泄漏,由於ActualWidth是依賴屬性--> <TextBlock Text="{Binding ElementName=layoutRoot, Path=ActualWidth}" /> <!--不會內存泄漏,由於Mode = OneTime--> <TextBlock Text="{Binding ElementName=layoutRoot, Path=Children.Count, Mode = OneTime}" />
這個都很是熟悉,很少說了。主要是經過using語句,或者在try { … } finally { … }中調用Dispose或者Close方法來釋放非託管資源。