1

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

为了解决这个问题,我创建了一个有 2 个空白页的新项目。每页有 2 个文本块用于打印当前内存和峰值内存,以及一个用于移动到下一页或上一页的按钮。当从第 1 页导航到第 2 页时,我对所有 3 件事进行空引用并调用 gc.collect 来销毁页面引用。同样,从第 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) 我为文本块和按钮设置引用为空的方法是否正确?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;
    }

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

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

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

4

1 回答 1

1

我在开发 WP8 应用程序时遇到了同样的问题。当您覆盖该OnBackKeyPress方法时,准确地说,在您的第二页上,您需要从堆栈(或JournalEntry)中删除该页面,因为如果不这样做,您会将其留在堆栈中,并且它无法被 GC 拾取。您需要添加NavigationService.RemoveBackEntry();OnBackKeyPress方法中,重要的是首先调用NavigationService.RemoveBackEntry();然后执行您想要的操作。

于 2013-04-30T13:55:04.193 回答