I have this code, and no matter what I do I keep getting a memory leak from the DataGrid data update. I've been looking at all the other answers to this problem here for days and I haven't found anything that works for me. I have a WPF window and this code to update the data (it is a small version of what happens in the real code, but I get the same bug).
I have this WPF code:
<Window x:Class="TremendoMemoryLeak.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:TremendoMemoryLeak"
mc:Ignorable="d"
DataContext="{Binding RelativeSource={RelativeSource Self}}"
Title="MainWindow" Height="450" Width="800">
<Grid>
<DataGrid ItemsSource="{Binding Hmis, Mode=OneWay}" AutoGenerateColumns="False" IsReadOnly="True">
<DataGrid.Columns>
<DataGridTemplateColumn Header="Estado">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<Ellipse Fill="{Binding Estado}" HorizontalAlignment="Left" Height="25" Stroke="Black" VerticalAlignment="Top" Width="25"/>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
<DataGridTextColumn Header="Dato1" Binding="{Binding Dato1}"/>
<DataGridTextColumn Header="Dato2" Binding="{Binding Dato2}"/>
</DataGrid.Columns>
</DataGrid>
</Grid>
</Window>
This class code:
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window, INotifyPropertyChanged
{
public ObservableCollection<Datos> Hmis { get; } = new ObservableCollection<Datos>();
private System.Threading.Timer timer;
public MainWindow()
{
InitializeComponent();
timer = new System.Threading.Timer(ActualizacionUI_Tick, null, 1000, 1000);
}
public event PropertyChangedEventHandler? PropertyChanged;
private void ActualizacionUI_Tick(object data)
{
Datos dato1 = new Datos() { Dato1 = "1", Dato2 = "2" };
Datos dato2 = new Datos() { Dato1 = "1", Dato2 = "2" };
Datos dato3 = new Datos() { Dato1 = "1", Dato2 = "2" };
Dispatcher.Invoke(() =>
{
dato1.Estado = new SolidColorBrush((Color)ColorConverter.ConvertFromString("#FF5DC75D"));
dato2.Estado = new SolidColorBrush((Color)ColorConverter.ConvertFromString("#FF5DC75D"));
dato3.Estado = new SolidColorBrush((Color)ColorConverter.ConvertFromString("#FF5DC75D"));
Hmis.Clear();
Hmis.Add(dato1);
Hmis.Add(dato2);
Hmis.Add(dato3);
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("Hmis"));
});
}
}
And this data class:
public class Datos : INotifyPropertyChanged
{
public Brush Estado { get; set; }
public string Dato1 { get; set; }
public string Dato2 { get; set; }
public event PropertyChangedEventHandler? PropertyChanged;
}
CodePudding user response:
I was executing the solution on Visual Studio 2022, and upon testing it on VS2019, the memory leak is suddenly gone, so it seems to be an issue in the 2022 preview.
CodePudding user response:
I changed the timer period to 50 ms and run the program in debug for 80mn (~100 000 calls to ActualizacionUI_Tick
) the memory usage is stable and around 123mb.
When you start the application there is indeed a period of time where the memory usage increase (and then it stabilize). Using JetBrains dotMemory it appears that the surviving objects are related to ConditionalWeakTable
implementation and retained by the MS.Internal.WeakEventTable
which is cleaned-up once in awhile on the will of some internal heuristic.