通过绑定(+ repro代码)使用Pivot的ItemsSource属性时内存泄漏

时间:2013-02-24 13:33:20

标签: c# windows-phone-7 windows-phone-8

在我的应用程序中,用户使用像书本一样的枢轴,他翻转枢轴项目,直到他击中最后一个,然后我删除现有的枢轴项目并加载新项目。这只需将Pivot.ItemsSource属性指向新的项集合即可完成。

我注意到加班时内存消耗增加并且永远不会降低。似乎Pivot的VisualTree没有收集垃圾。

我已经创建了一个示例应用程序来演示问题(这是一个WP8应用程序):

重现的步骤:

  • 启动应用
  • 导航至Page1
  • 多次单击“加载更多”按钮。

    (一次加载100件物品当然不是我真实的    应用程序,但它清楚地演示了内存    消费每次都越来越高,即使导航回来也不会被清除)

我会感激任何降低内存的提示或建议,就像它的方式一样,如果应用程序以这种方式使用足够长的时间,应用程序将不可避免地崩溃。

MainPage.xaml中:

...
<HyperlinkButton NavigateUri="/Page1.xaml">
    Page1
</HyperlinkButton>
...

MainPage.xaml.cs中:

    //...
    public MainPage()
    {
        InitializeComponent();
        var timer = new DispatcherTimer();
        timer.Interval = TimeSpan.FromSeconds(2);
        timer.Tick += delegate
                          {
                              Debug.WriteLine("{0:f} MB, {1:f} MB",
                                              DeviceStatus.ApplicationCurrentMemoryUsage/(1024.0*1024),
                                              DeviceStatus.ApplicationPeakMemoryUsage/(1024.0*1024));
                          };
        timer.Start();
    }
    //...

的Page1.xaml:

<Grid x:Name="LayoutRoot" Background="Transparent">
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto" />
            <RowDefinition Height="*" />
        </Grid.RowDefinitions>

        <!--TitlePanel contains the name of the application and page title-->
        <StackPanel Grid.Row="0" Margin="12,17,0,28">
            <TextBlock Text="MY APPLICATION" Style="{StaticResource PhoneTextNormalStyle}" />
            <TextBlock Text="page name" Margin="9,-7,0,0" Style="{StaticResource PhoneTextTitle1Style}" />
        </StackPanel>

        <!--ContentPanel - place additional content here-->
        <Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">

            <StackPanel>
                  <phone:Pivot x:Name="pivot1" ItemsSource="{Binding Items}">
                    <!--Pivot item one-->
                    <phone:Pivot.ItemTemplate>
                        <DataTemplate>
                            <TextBlock Text="{Binding}" />
                        </DataTemplate>
                    </phone:Pivot.ItemTemplate>
                </phone:Pivot>
                <Button Click="Load_More">Load More</Button>
            </StackPanel>
        </Grid>
    </Grid>

Page1.xaml.cs:

public partial class Page1 : PhoneApplicationPage, INotifyPropertyChanged
    {
        private List<int> _items;
        public List<int> Items
        {
            get
            {
                if (_items == null)
                {
                    _items = new List<int>();
                }
                return _items;
            }

            set
            {
                _items = value;
                RaisePropertyChanged("Items");
            }
        }
        public Page1()
        {
            InitializeComponent();
            DataContext = this;
        }

        private void Load_More(object sender, RoutedEventArgs e)
        {
            var lst = new List<int>();
            //100 new items just for demonstration, in reality i won't have more than 6 new items
            for (int i = 0; i < 100; i++)
            {
                lst.Add(i);
            }
            pivot1.SelectedIndex = 0;
            Items=lst;
        }

        public event PropertyChangedEventHandler PropertyChanged;

        void RaisePropertyChanged(string property)
        {
            var handler = PropertyChanged;
            if (handler != null)
            {
                handler(this, new PropertyChangedEventArgs(property));
            }
        }

      ~Page1()
      {
          Debug.WriteLine("Page1 GC");
      }
    }

3 个答案:

答案 0 :(得分:2)

似乎Pivot控件泄漏,正如使用Panorama控件所示。 用这个替换你的堆栈面板(我没有更改控件的名称)不会泄漏。 (记忆得到回收约50兆)

        <StackPanel>
            <Button Click="Load_More">Load More</Button>
            <phone:Panorama x:Name="pivot1" ItemsSource="{Binding Items}">
                <phone:PanoramaItem></phone:PanoramaItem>
            </phone:Panorama>
        </StackPanel>

答案 1 :(得分:1)

一种解决方法是继续重复使用相同的项目集合,而不是创建新的集合。当您需要更改它时,清除该集合,然后重新填充它。该集合可以驻留在App全局空间中,例如:

public partial class App : Application
    {
        public static List<int> GlobalList;
...
    }

在MainPage构造函数中初始化它,然后通过App.GlobalList引用它。

答案 2 :(得分:1)

解决方案1 ​​

也许你可以尝试这个解决方案:Windows Phone 8: LongListSelector Memory Leak

尝试在关闭页面之前清除这些依赖项属性。

解决方案2

尝试使用OservableCollection<T>代替List<T>来绑定Itemsource。将List<T>绑定到Itemsource可能会因WPF设计而导致内存泄漏。

A memory leak may occur when you use data binding in Windows Presentation Foundation