WP7导航中的内存泄漏问题 - 列表框绑定

时间:2012-07-04 06:12:03

标签: windows-phone-7.1

我正在为Windows Phone 7开发Silverlight中的一个应用程序。我陷入了Windows手机应用程序中常见的问题,但无法以任何方式摆脱它。从第一页到第二页,第二页到第一页等导航过程中会出现内存泄漏问题,等等多次出现。

要解决这个问题,我创建了一个有2个空白页面的新项目。每页有2个文本块用于打印当前内存和峰值内存,还有一个按钮用于移动到下一页或上一页。当从第1页导航到第2页时,我对所有3个内容进行null referance并调用gc.collect来销毁页面referance。同样的,当从第2页移到第1页时,我也会做同样的事情。

我还尝试在计时器中每500毫秒调用gc.collect(),但仍然没有结果。如果我完全删除gc.collect(),内存增加MB,所以我认为这是必须的。

以下是我的代码片段:

主页:

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Windows;
    using System.Windows.Controls;
    using Microsoft.Phone.Controls;
    using System.Windows.Threading;

    namespace AppMemory
    {
        public partial class MainPage : PhoneApplicationPage
        {

            // Constructor
            public MainPage()
            {
                InitializeComponent();

                txtCM.Text = "C : " + Microsoft.Phone.Info.DeviceStatus.ApplicationCurrentMemoryUsage.ToString();
                txtPM.Text = "P: " + Microsoft.Phone.Info.DeviceStatus.ApplicationPeakMemoryUsage.ToString();
            }

            // Simple button Click event handler to take us to the second page
            private void Button_Click(object sender, RoutedEventArgs e)
            {
                NavigationService.Navigate(new Uri("/Page1.xaml", UriKind.Relative));
            }

            protected override void OnBackKeyPress(System.ComponentModel.CancelEventArgs e)
            {
                while (this.NavigationService.BackStack.Any())
                {
                    this.NavigationService.RemoveBackEntry();
                }
            }

            protected override void OnNavigatedTo(System.Windows.Navigation.NavigationEventArgs e)
            {
                while (this.NavigationService.BackStack.Any())
                {
                    this.NavigationService.RemoveBackEntry();
                }
            }
            protected override void OnNavigatedFrom(System.Windows.Navigation.NavigationEventArgs e)
            {
                dosposeMemory();
                base.OnNavigatedFrom(e);
                this.DataContext = null;
                GC.Collect();
            }

            public void dosposeMemory()
            {
                try
                {
                    if (txtCM != null)
                    {
                        txtCM.Text = null;
                        txtCM = null;
                    }

                    if (txtPM != null)
                    {
                        txtPM.Text = null;
                        txtPM = null;
                    }

                    if (btn1 != null)
                    {
                        btn1.Click -= Button_Click;
                        btn1.Style = null;
                        btn1.Resources.Clear();
                        btn1.Resources = null;
                        btn1 = null;
                    }

                    if (ContentPanel != null)
                    {
                        ContentPanel.Children.Clear();
                        ContentPanel.Resources.Clear();
                        ContentPanel.Resources = null;
                        ContentPanel = null;
                    }

                    if (LayoutRoot != null)
                    {
                        LayoutRoot.DataContext = null;
                        LayoutRoot.Background = null;
                        LayoutRoot.Resources.Clear();
                        LayoutRoot.Resources = null;
                        LayoutRoot.Children.Clear();
                        LayoutRoot = null;
                    }

                  if (app1 != null)
                    {
                        app1.Resources.Clear();
                        app1.Resources = null;
                        app1 = null;
                    }

                    GC.Collect();
                }
                catch(Exception)
                {

                }
            }

            ~MainPage()
            {
                System.Windows.Deployment.Current.Dispatcher.BeginInvoke(new System.Action(() =>
                {
                    GC.Collect();
                }));
            }
        }
    }

第二页:

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Net;
    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Documents;
    using System.Windows.Input;
    using System.Windows.Media;
    using System.Windows.Media.Animation;
    using System.Windows.Shapes;
    using Microsoft.Phone.Controls;

    namespace AppMemory
    {
        public partial class Page1 : PhoneApplicationPage
        {
            public Page1()
            {
                InitializeComponent();
                textBlock1.Text = "C : " + Microsoft.Phone.Info.DeviceStatus.ApplicationCurrentMemoryUsage.ToString();
                textBlock2.Text = "P: " + Microsoft.Phone.Info.DeviceStatus.ApplicationPeakMemoryUsage.ToString();
            }
            protected override void OnBackKeyPress(System.ComponentModel.CancelEventArgs e)
            {
                while (this.NavigationService.BackStack.Any())
                {
                    this.NavigationService.RemoveBackEntry();
                }

                NavigationService.Navigate(new Uri("/MainPage.xaml", UriKind.Relative));
            }
            protected override void OnNavigatedTo(System.Windows.Navigation.NavigationEventArgs e)
            {
                while (this.NavigationService.BackStack.Any())
                {
                    this.NavigationService.RemoveBackEntry();
                }
            }
            protected override void OnNavigatedFrom(System.Windows.Navigation.NavigationEventArgs e)
            {
                dosposeMemory();
                base.OnNavigatedFrom(e);
                this.DataContext = null;
                GC.Collect();
            }
            public void dosposeMemory()
            {
                try
                {
                    if (textBlock1 != null)
                    {
                        textBlock1.Text = null;
                        textBlock1 = null;
                    }

                    if (textBlock2 != null)
                    {
                        textBlock2.Text = null;
                        textBlock2 = null;
                    }

                    if (ContentPanel != null)
                    {
                        ContentPanel.Children.Clear();
                        ContentPanel.Resources.Clear();
                        ContentPanel.Resources = null;

                        ContentPanel = null;
                    }
                    if (LayoutRoot != null)
                    {
                        LayoutRoot.Children.Clear();
                        LayoutRoot.Resources.Clear();
                        LayoutRoot.Resources = null;

                        LayoutRoot = null;
                    }
                    if (page1 != null)
                    {
                        page1.Resources.Clear();
                        page1.Resources = null;
                        page1 = null;
                    }
                    GC.Collect();
                }
                catch (Exception)
                {
                    GC.Collect();
                }
            }
        }
    }

以下是对每次尝试增加的当前记忆的跟踪:

    Try Page 1      Page 2
    1   7426048         7442432
    2   6959104     8257536
    3   6934528     8454144
    4   8622080     8458240
    5   8626176     8470528
    6   8630272     8470528

问题: 1)我的流程和方法是否适合导航和管理内存? 2)我的方法是为文本块和按钮设置referance null是否合适? 3)同样在我的实际项目中,我在列表框中使用数据绑定,我已经按照以下方式进行了搜索。

    if (listCountry != null)
    {
        listCountry.SelectionChanged -= listCountry_SelectionChanged;
        //listCountry.Items.Clear();
        listCountry.DataContext = null;
        listCountry.ItemsSource = null;
        listCountry.Resources.Clear();
        listCountry.Resources = null;
        listCountry = null;
    }

我对此有疑问,因为在我的项目中,这种列表框有多种用法。

请带我离开,因为我花了很多时间进行研究和更新,但没有得到当前和峰值内存的解决方案。

提前致谢。 大卫雅各布斯。

1 个答案:

答案 0 :(得分:1)

我在开发WP8应用时遇到了同样的问题。当您覆盖OnBackKeyPress方法时,在第二页上确切地说,您需要从堆栈中删除页面(或JournalEntry),因为如果不这样做,则将其保留在堆栈中不能被GC拿起。您需要将NavigationService.RemoveBackEntry();添加到OnBackKeyPress方法,首先调用NavigationService.RemoveBackEntry();然后执行您想要的操作非常重要。