0

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.

jeiea
  • 1,965
  • 14
  • 24
  • Clear LvTest.ItemsSource before you null it. – PepitoSh Jul 10 '18 at 03:32
  • @PepitoSh Then should I add `(listView.ItemsSource as IList).Clear();` in `OnClosed()` every time like this without benefit of GC? – jeiea Jul 10 '18 at 03:44
  • @jeiea The core problem is that you think that your existing code will GC everything. It won't. It won't _necessarily_ collect / compact the Large Object Heap. A byte array of size `100000000` will be on the LOH. Now, keeping that in mind, read the duplicate link. – mjwills Jul 10 '18 at 03:48
  • @mjwills Then why `new List()` works? – jeiea Jul 10 '18 at 03:49
  • The short answer is 'it doesn't work'. It must be altering the behaviour of the system just enough that compaction of the LOH is kicking in. In other words, you got lucky. _Did you try setting https://msdn.microsoft.com/en-us/library/system.runtime.gcsettings.largeobjectheapcompactionmode.aspx before calling `GC.Collect`? Does that work?_ – mjwills Jul 10 '18 at 03:51
  • Are you testing in the IDE with Debug build? Does it behave differently outside of the IDE with Release build? GC behaviour can _seem_ different inside the IDE. – mjwills Jul 10 '18 at 03:54
  • We had similar problems with the indeterministic nature of GC. We found that objects get collected much faster when we break chained references as opposed to wait for the GC to do it gradually. It is a hocus-pocus per se, but it worked for us. – PepitoSh Jul 10 '18 at 03:54
  • @mjwills @PepitoSh I ran this on .NET 4.5 Debug, which doesn't have `LargeObjectHeapCompactionMode` setting. And I don't think this is GC problem. I just found some clue with `ObservableCollection`. – jeiea Jul 10 '18 at 04:02

1 Answers1

0

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);
jeiea
  • 1,965
  • 14
  • 24