question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Use binding in transform cause memory leak in VS 2022

See original GitHub issue
  • .NET Core Version: 6.0, 4.5
  • Windows version: 19044.1826
  • Does the bug reproduce also in WPF for .NET Framework 4.8?: Yes in 4.5.
  • Is this bug related specifically to tooling in Visual Studio (e.g. XAML Designer, Code editing, etc…)? Yes, only in VS2022.

Problem description: I have a DataTemplate which contains a RotateTransform whose Angle is bound to the model. When I add models to a ItemsControl and then remove them, the memory usage won’t fall to initial value and the object count will increase.

Actual behavior: As the sample code below, when the button is clicked, 10,000 models will be added to the window and then be removed. But the memory usage and object count remains. Most of the objects are WeakReference, ConditionalWeakTable<Object, Object>, ConditionalWeakTable+Container<Object, Object>, WeakEventManager+ListenerList<EventArgs>.

Timeline memory object count
initial 61M 34196
clicked 133M 155440

Expected behavior: If I delete the transform or delete the binding, the memory usage and object count will decrease.

Timeline memory object count
initial 62M 34227
clicked 107M 34461

Minimal repro: MainWindow.xaml

<Window x:Class="WPFTransformBindingMemoryLeak.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:WPFTransformBindingMemoryLeak"
        mc:Ignorable="d"
        Title="MainWindow" Height="450" Width="800">
    <Window.Resources>
        <DataTemplate DataType="{x:Type local:Shape}">
            <Border Background="SandyBrown">
                <Border.RenderTransform>
                    <RotateTransform Angle="{Binding Angle}"/>
                </Border.RenderTransform>
                <TextBlock Text="The Shape"/>
            </Border>
        </DataTemplate>
    </Window.Resources>
    <Grid>
        <Button Content="start" Name="startB" Click="startB_Click" Width="100" Height="100"/>
        <ItemsControl x:Name="container"/>
    </Grid>
</Window>

MainWindow.xaml.cs

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Windows;

namespace WPFTransformBindingMemoryLeak
{
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
        }

        private void startB_Click(object sender, RoutedEventArgs e)
        {
            for (int i = 0; i < 100; i++)
            {
                List<Shape> packages = new List<Shape>();
                for (int j = 0; j < 100; j++)
                    packages.Add(new Shape());
                Dispatcher.BeginInvoke(System.Windows.Threading.DispatcherPriority.Background, new Action(() =>
                {
                    for (int j = 0; j < 100; j++)
                        container.Items.Add(packages[j]);
                }));
                Dispatcher.BeginInvoke(System.Windows.Threading.DispatcherPriority.Background, new Action(() =>
                {
                    for (int j = 0; j < 100; j++)
                        container.Items.Remove(packages[j]);
                }));
            }
            Dispatcher.BeginInvoke(System.Windows.Threading.DispatcherPriority.ApplicationIdle, new Action(() =>
            {
                GC.Collect();
            }));
        }
    }

    public class Shape : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler? PropertyChanged;
        private double angle;
        public double Angle
        {
            get { return angle; }
            set
            {
                angle = value;
                PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(Angle)));
            }
        }

    }
}

Issue Analytics

  • State:open
  • Created a year ago
  • Reactions:1
  • Comments:10 (1 by maintainers)

github_iconTop GitHub Comments

2reactions
yll690commented, Mar 8, 2023

Yes, disabling XAML Hot Reload resolves the issue. Thank you.

2reactions
asundheimcommented, Feb 22, 2023

If you open up the problematic snapshots, you’ll see VS types holding on to your memory (such as Microsoft.VisualStudio.DesignTools.WpfTap.*), which I’ve been told is due to XAML Hot Reload. We’re working on adding a warning to indicate the snapshot may not accurately reflect memory usage due to this, but you can try disabling XAML Hot Reload and seeing if that resolves your issue.

Read more comments on GitHub >

github_iconTop Results From Across the Web

Avoiding Memory Leaks in Visual Studio Editor Extensions
For now, though, here's some DOs and DON'Ts for crafting leak free VS Editor extensions with the existing in-process extensibility model.
Read more >
Can bindings create memory leaks in WPF?
This behavior keeps the reference alive between the PropertyDescriptor and the object as the target remains in use. This can cause a memory...
Read more >
Find, Fix, and Avoid Memory Leaks in C# .NET: 8 Best ...
The rule of thumb is to always bind to a DependencyObject or to a ** INotifyPropertyChanged object. When you fail to do so,...
Read more >
Avoiding memory leaks when using Data Binding and View ...
When using Data Binding we used to add the binding as a lateinit var to our fragment like this: This leads to a...
Read more >
Diagnosing memory leaks in .NET apps - YouTube
In this episode, Software Engineer, Mike Rousos, joins Rich to show can we can use tools like dotnet-dump and Visual Studio to diagnose ......
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found