1

I've discovered a strange problem with one of my layouts. When using a Grid RowDefinition with Height=Auto, the application takes much longer to startup and consumes 5x as much memory. I've managed to create a sample application to demonstrate:

MainWindow.xaml

<Window x:Class="MemoryHog.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:mh="clr-namespace:MemoryHog"
        Title="MainWindow" Height="350" Width="525">
    <Window.Resources>
        <mh:DataSource x:Key="DataSource"/> <!-- 15000 strings-->
    </Window.Resources>
    <Grid>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="*"/>
            <ColumnDefinition Width="Auto"/>
        </Grid.ColumnDefinitions>
        <Grid.RowDefinitions>
            <RowDefinition Height="*" />
            <RowDefinition Height="Auto" /> <!-- "Auto" = 112mb, "22" = 22mb. Auto takes much longer to startup -->
        </Grid.RowDefinitions>
        <ListView Grid.Column="1" Grid.Row="0" Width="200" DataContext="{StaticResource DataSource}" ItemsSource="{Binding Items}"/>
        <StatusBar Grid.ColumnSpan="2" Grid.Row="1" />
    </Grid>
</Window>

DataSource.cs

using System;
using System.Collections.ObjectModel;

namespace MemoryHog
{
    class DataSource
    {
        public DataSource()
        {
            this.Items = new ObservableCollection<String>();

            for (int i = 0; i < 15000; ++i)
            {
                this.Items.Add(String.Format("{0}", i + 1));
            }
        }

        public ObservableCollection<String> Items { get; set; }
    }
}

Look at my comment in MainWindow.xaml, if you set the RowDefinition.Height to Auto the app will consume 112MB of memory, but if you change it to be 22, the app will only consume 22MB! What is going on here? Is this a bug?


Edit The memory increase is directly proportional to the number of items in the ListView, and the memory stays allocated forever.

Mark Ingram
  • 71,849
  • 51
  • 176
  • 230
  • Probably that is the feature of WPF, not bug. If that memory goes away with time, that's okay. – Jack Malkovich Jun 12 '14 at 21:35
  • What happens if you put the StatusBar above the ListView in the XAML? You have a lot of data being loaded (which you should probably try to Virtualize if possible, but that's a separate issue), so you're likely triggering a lot of measure/arrange passes as the visual tree gets updated. The order of the child elements in the Grid might possibly have an impact on how this calculation gets performed, but in general it's always going to be more complicated when more than one column has automatic or proportional sizing. – Dan Bryant Jun 12 '14 at 21:47
  • @JackMalkovich No, the memory usage doesn't drop over time! – Mark Ingram Jun 12 '14 at 21:54
  • @DanBryant The order in the XAML makes no difference. Virtualization helps a little with the memory usage, but it's still higher than it should be. – Mark Ingram Jun 12 '14 at 21:56

1 Answers1

3

Setting the RowDefinition.Height to Auto effectively breaks UI virtualization, by putting your 15000 rows-long ListView in an "infinite container" where it gets as much vertical size as it wants, and is not restricted by anything. This means that all 15000 ListViewItems are effectively created (unnecessarily, because they're not displayed on screen due to screen size restrictions).

Use a DockPanel or leave the Height untouched: <RowDefinition/>.

Federico Berasategui
  • 43,562
  • 11
  • 100
  • 154