简体   繁体   中英

WPF Listbox memory leak

Here's my xaml:

<ListBox Grid.Row="4" HorizontalAlignment="Stretch" Margin="10,132,10,10"  ScrollViewer.VerticalScrollBarVisibility="Disabled" Name="lbStatus" VerticalAlignment="Stretch" VirtualizingStackPanel.IsVirtualizing="True" VirtualizingStackPanel.VirtualizationMode="Recycling"/>

and my C# code:

  public void DisplayStatusMessage(string msg)  
  {
       if (lbStatus.Dispatcher.CheckAccess())
       {
          AddMessage(msg, Brushes.Black);
       }
       else
       {
          this.Dispatcher.BeginInvoke((Action)(() =>
          {
            AddMessage(msg, Brushes.Black);
           }));
       }   
  }



  private void AddMessage(string msg)
  {
     ListBoxItem status = new ListBoxItem();
     status.Content = DateTime.Now.ToString("MM-dd-yyyy HH:mm:ss:fff ") + msg;

     lbStatus.Items.Add(status);
     lbStatus.ScrollIntoView(status);
     status = null;
   }

I am calling DisplayStatusMessage within while (true) loop to display status on the listbox. My application grows considerably in size overnight, which seems to indicate a memory leak on the listbox. Is there an alternative to the listbox to display infinite status ? I thought setting the Virtualization to recycling would prevent from leaking ?

This isn't a 'leak' per se. If you are continually adding entries to a ListBox , overnight even, you're likely going to have thousands of entries, which will of course require memory to store.

To avoid this, you could remove old entries as you add new ones:

if (listbox.Items.Count > 100)
    listbox.Items.RemoveAt(0); // 0 or 99, whichever is your oldest
listbox.Items.Add(status);
listbox.ScrollIntoView(status);

ListBox has a leak if a 'DataTemplate' is assigned. Even if you just put a TextBox in it you can measure a considerable memory leak. I found a solution by replacing it by 'ListView'. 'ListView' has seemingly noticed this leak and Microsoft's solution was to add a protected method 'ClearContainerForItemOverride'. This is called for each ListViewItem (the container for the data item) that is not used anymore. Now we can also use that to clear all the allocated stuff and attached event handlers that would prevent the content of our DataTemplate to be collected by the Garbage Collector. It depends on what you have inside the DataTemplate. So I just called a public Event there for the client of the 'ListView' so s/he can put the code there. In my case I had only one TextBox, which resulted in this code:

    private void lstLog_ClearListViewItemContainer(object sender,
        ClearListViewItemContainerEventArgs clearListViewItemContainerEventArgs)
    {
        ContentPresenter contentPresenter = VisualTree.FindChild<ContentPresenter>(
            clearListViewItemContainerEventArgs.ListViewItem, null, true);
        if (contentPresenter != null)
        {
            Control control = VisualTree.FindChild<Control>(contentPresenter, null, true);
            if (control != null)
            {
                TextBox txtLog = (TextBox)control;
                txtLog.GotFocus -= txtLog_GotFocus;
                txtLog.PreviewMouseDown -= txtLog_PreviewMouseDown;
                txtLog.SelectionChanged -= txtLog_SelectionChanged;
                txtLog.ContextMenu = null;  // cut the reference from the context menu back to the textbox
                BindingOperations.ClearBinding(txtLog, TextBox.TextProperty);
                BindingOperations.ClearBinding(txtLog, TextBox.ForegroundProperty);
                txtLog.Foreground = null;
                txtLog.Resources = null;
            }

            contentPresenter.DataContext = null;
            contentPresenter.ContentTemplate = null;
            contentPresenter.Content = null;
            contentPresenter.Resources = null;
        }
    }

To 'VisualTree': Searches for the first child of type T in depth. Custom made typed version of the .NET 'VisalTreeHelper'.

I think not all of the cleaning code is necessary, but better too much than too less. A measurement of the memory usage showed that the leak vanished this way.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM