为什么我在UWP / C#应用程序中遇到内存故障/泄漏

时间:2017-04-02 20:07:46

标签: c# memory uwp

我创建了IOrderedIEnumerable的扩展程序 看起来像这样:

internal static ObservableCollection<T> ToObservableCollection<T>(this IOrderedEnumerable<T> list)
{
    var observableCollection = new ObservableCollection<T>();
    foreach (var p in list)
        observableCollection.Add(p);
    return observableCollection;
}

我还有一个看起来像这样的页面:

private ObservableCollection<BusStopName> _ListOfBusStopNames;

public BusStopsListPage()
{
    this.InitializeComponent();
    this.SetIsBackFromPageAllowed(true);

    _ListOfBusStopNames = Timetable.Instance.BusStopsNames
                                   .OrderBy(p => p.Name)
                                   .ToObservableCollection<BusStopName>();
}

在此页面中,我有一个与_ListOfBusStopNames

绑定的列表视图

Timetable.Instance.BusStopsNames有2812个条目。

当我导航到此页面时,应用程序内存正在增长到无穷大数字。看起来像(红线是导航到此页面的时刻):

enter image description here

在内存快照中我们可以看到这件事正在解决这个问题: enter image description here

我不知道它是什么。 有人有任何想法吗?

当我将实例构造函数更改为:

public BusStopsListPage()
{
    this.InitializeComponent();
    this.SetIsBackFromPageAllowed(true);

    _ListOfBusStopNames = new ObservableCollection<BusStopName>();
}

一切都很好。此外,当我在此构造函数中手动将ListTimetable.Instance.BusStopsNames)更改为ObservableCollection时,它的效果也很好。

修改 嗯..我试图做一个例子如何重现它,我得到一个解决方案。这是非常令人困惑的,所以如果有人能解释为什么会发生这种情况会很好:)

  1. 创建UWP APP
  2. 仅在MainPage.xaml中添加:<Frame Name="MainFrame" />
  3. 在代码隐藏中:this.Loaded += (s, e) => MainFrame.Navigate(typeof(BlankPage1));
  4. 创建名为BlankPage1
  5. 的新空白页
  6. 在BlankPage视图中添加:

    <Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
        <StackPanel> 
            <ListView ItemsSource="{x:Bind _ListOfTestClasses}">
                <ListView.ItemTemplate>
                    <DataTemplate x:DataType="local:TestClass">
                        <Grid>
                            <TextBlock Text="{x:Bind Name}" />
                        </Grid>
                    </DataTemplate>
                </ListView.ItemTemplate>
            </ListView>
        </StackPanel>
    </Grid>
    
  7. 在代码隐藏中:

        public sealed partial class BlankPage1 : Page
        {
            private List<TestClass> _List;
            private ObservableCollection<TestClass> _ListOfTestClasses;
            public BlankPage1() {
                this.InitializeComponent();
                GenerateTestData();
                _ListOfTestClasses = _List.OrderBy(p => p.Name).ToObservableCollection<TestClass>();
            }
            private void GenerateTestData() {
                _List = new List<TestClass>();
                for(int i = 0; i < 2800; i++)
                    _List.Add(new TestClass() { Id = i, Name = Guid.NewGuid().ToString() });
            }
        }
    
        public static class Extension {
            public static ObservableCollection<T> ToObservableCollection<T>(this IOrderedEnumerable<T> list) {
                var observableCollection = new ObservableCollection<T>();
                foreach (var p in list)
                    observableCollection.Add(p);
                return observableCollection;
            }
        }
        public class TestClass {
            public int Id { get; set; }
            public string Name { get; set; }
        }
    
  8. 运行应用

  9. 所以..你可以看到应用程序滞后,内存占用越来越多..现在......尝试删除BlankPage1视图StackPanel。现在运行应用程序。

1 个答案:

答案 0 :(得分:1)

这是一个常见问题。问题是在XAML中滥用面板。 Grid将伸展以适应其容器的边界,并将其级联到其子级。 StackPanel只会级联相反方向的大小。

例如,当您有<StackPanel Orientation="Vertical"/>时,所有孩子都会获得父Grid的宽度,但不会获得高度。因为方向是垂直的,所以高度将是无限的,以允许面板根据其请求的高度堆叠其子节点。

如果您有<StackPanel Orientation="Horizontal"/>,则所有孩子都会获得父Grid的高度,但不会获得宽度。与上述相同的原因。它需要水平堆叠。

所以...... ,当<ListView/>内有<StackPanel/>时:

<StackPanel>
   <ListView>...</ListView>
</StackPanel>

StackPanel告诉ListView使用height = infinity渲染其大小。因此,ListView中的所有2,800个项目实际上都在呈现,而不是虚拟化。

当方向相同时,您必须避免将ListView放在StackPanel中。

这应该有效:

<Grid>
   <StackPanel Orientation="Horizontal">
      <ListView>...</ListView>
   </StackPanel>
</Grid>

......但这太傻了。