Search code examples
c#wpfmemory-leaks.net-4.5

How can I release ListView's source memory?


I want to release ListView's ItemsSource reference immediately in case the reference holds large memory.

But GC doesn't release the reference even though I don't have any reference in my code. For example, I expected freeing byte[] with the below 'Free' button.

SimpleListView.xaml

<Window x:Class="PlayWPF.SimpleListView"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="SimpleListView" Height="450" Width="800">
  <DockPanel LastChildFill="True">
    <ListView Name="LvTest" Width="500" DockPanel.Dock="Left"/>
    <Button Content="Alloc" Click="AllocClick" Height="200" DockPanel.Dock="Top"/>
    <Button Content="Free" Click="FreeClick"/>
  </DockPanel>
</Window>

SimpleListView.xaml.cs

public partial class SimpleListView : Window {
  public SimpleListView() {
    InitializeComponent();
  }

  private void AllocClick(object sender, RoutedEventArgs e) {
    var list = new List<byte[]>();
    list.Add(new byte[100000000]);
    LvTest.ItemsSource = list;
  }

  private void FreeClick(object sender, RoutedEventArgs e) {
    LvTest.ItemsSource = null;
    //LvTest.ItemsSource = new List<int>();
    GC.Collect(GC.MaxGeneration, GCCollectionMode.Forced);
    GC.WaitForPendingFinalizers();
  }
}

Clicking 'Free' button makes no difference, with new List<int>(), it release the reference on second trial. The reference stays alive even if I close window.

How can I release it desirably?

EDIT: It had been marked possible duplicate of Why Large Object Heap and why do we care?, but changing LargeObjectHeapCompactionMode on .NET 4.7.1 has no effect.

I found the solution, using ObservableCollection instead of plain List which answers original question but I don't know how and why this makes difference. For left curiosity I leave this question open.


Solution

  • It was described on a currently deleted blog post.

    The TextBlock control has a binding to an object (myGrid) that has a reference back to the TextBlock (it is one of myGrid children’s).
    Note that this type of a DataBinding leak is unique to a specific scenario (and not to all DataBinding scenarios) as documented in the kb article. The property in the Path is a not a DependencyProperty and not on a class which implements INotifyPropertyChanged and in addition a chain of strong reverences must exist.

    According to that, I misused data binding, and correct free snippet is the below.

    BindingOperations.ClearBinding(MyTextBlock, TextBlock.TextProperty);