You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
This repository was archived by the owner on Feb 25, 2026. It is now read-only.
Repository navigation
This repository was archived by the owner on Feb 25, 2026. It is now read-only.
Memory retention issue persists after setting DataGrid to "null" #4986
I'm currently using the CommunityToolKit DataGrid in my application. Upon adding the DataGrid through a button, I observed that the application's memory usage increased from 98MB to 108MB. However, even after setting the DataGrid reference to null upon button click, the memory usage remains at 108MB instead of reverting back to the initial 98MB.
Additionally, I need confirmation on the proper method to dispose of the Community DataGrid. Is simply setting the DataGrid reference to null sufficient, or are there additional steps that need to be taken?
Regression
No response
Reproducible in sample app?
This bug can be reproduced in the sample app.
Steps to reproduce
1.Run the sample
2.Watch the process memory in the Diagnostic Tools.
3.Click Add Datagrid button.
4.Repeat step 2.
5.Click Dispose button.
6.Wait for few seconds and repeat step 2.
Expected behavior
My goal is to ensure that after setting the DataGrid reference to null, the application's memory usage returns to its original level of 98MB.
I have been using same DataGrid and recently recognized same issue.
After struggling with it for a week, I found reasonable bugs and solution.
There are two misused patterns in source code.
hmm... But in fact, it seems to be one.
First, WeakEventListener is not weak.
INotifyCollectionChanged notifyingDataSource1 = value as INotifyCollectionChanged;
if (notifyingDataSource1 != null)
{
_weakCollectionChangedListener = new ... (this);
_weakCollectionChangedListener.OnEventAction = ...
_weakCollectionChangedListener.OnDetachAction =
(weakEventListener) => notifyingDataSource1.CollectionChanged -= weakEventListener.OnEvent;
notifyingDataSource1.CollectionChanged += _weakCollectionChangedListener.OnEvent;
}
It's a snipet in DataGridDataConnection.WireEvents().
The handler to OnDetachAction event should be a Closure which refers to this DataGridDataConnection object through notifyingDataSource1 local variable. Because this DataGridDataConnection refers to DataGrid itself, GC will never reclaim DataGrid object if you don't call UnWireEvents() explicitly (or implicitly like changing ItemsSource to null).
Tick event also gets a Closure handler which refers to DataGrid itself, and DataGrid keeps a reference into the DispatcherQueueTimer object by _hideScrollBarsTimer member field. i.e. it's a typical circular reference case.
In general, the circular referencing is not wrong, GC is sufficiently capable in such case.
But, this is not the case. it seems like DispatcherQueueTimer object does never die.
The solution is the breaking circular reference. Dereference timer or detach the handler.
Ok, it's all.
I finally call DataGridDataConnection.UnWireEvents() and dereference DataGrid._hideScrollBarsTimer field with null using Reflection.
So far, I'm happy.
Activity
KamuJeong commentedon Mar 8, 2025
I have been using same DataGrid and recently recognized same issue.
After struggling with it for a week, I found reasonable bugs and solution.
There are two misused patterns in source code.
hmm... But in fact, it seems to be one.
First, WeakEventListener is not weak.
It's a snipet in DataGridDataConnection.WireEvents().
The handler to OnDetachAction event should be a Closure which refers to this DataGridDataConnection object through notifyingDataSource1 local variable. Because this DataGridDataConnection refers to DataGrid itself, GC will never reclaim DataGrid object if you don't call UnWireEvents() explicitly (or implicitly like changing ItemsSource to null).
Second, DispatcherQueueTimer is weired
In DataGrid.HideScrollBarsAfterDelay(),
Tick event also gets a Closure handler which refers to DataGrid itself, and DataGrid keeps a reference into the DispatcherQueueTimer object by _hideScrollBarsTimer member field. i.e. it's a typical circular reference case.
In general, the circular referencing is not wrong, GC is sufficiently capable in such case.
But, this is not the case. it seems like DispatcherQueueTimer object does never die.
The solution is the breaking circular reference. Dereference timer or detach the handler.
Ok, it's all.
I finally call DataGridDataConnection.UnWireEvents() and dereference DataGrid._hideScrollBarsTimer field with null using Reflection.
So far, I'm happy.