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.

DataGridView not dispose old elements

See original GitHub issue
  • .NET Core Version: all up to 7.0 p2

  • Have you experienced this same bug with .NET Framework?: Yes

Problem description: As I mentioned in https://github.com/dotnet/winforms/issues/6858 DataGridView not dispose old data on DataSource change. This is lead to 2 problems:

  1. All this stuff are going to finalization query because we have unnecessary finalizer here #6858.
  2. If we have a ContextMenuStrip bound to Cell/Column/Row we will have a memory leak. DataGridView with 3 columns and ContextMenuStrip bound to 1000 rows, result of DS refresh: image

Expected behavior: Old data must be property disposed. Probably in DataGridView.RefreshColumnsAndRows() (in DataGridView.Methods.cs)

Minimal repro: DataGridViewLeak.zip

Issue Analytics

  • State:open
  • Created 2 years ago
  • Comments:11 (11 by maintainers)

github_iconTop GitHub Comments

3reactions
kirsan31commented, Apr 3, 2022

I need a conceptual help here 😔 What did I find out while investigating all this dispose stuff in DataGridView:

  1. DataGridView does not care about the disposing of it’s components at all.
  2. Due to finalizers (empty) in base components (DataGridViewBand, DataGridViewCell) all of them are end in Freachable queue. And it has drastically performance impact on apps with many constantly updating DataGridViews.
  3. As we cannot remove this finalizers we need implement properly dispose logic. And then I stalled 😕

My first attempt was dispose rows and cells only on databound DataGridView datasource change. But there were many downsides:

  • Оnly whole datasource change was processed (removing rows in existing datasource still was not disposed).
  • Subcomponents (like rowheaders) still was not disposed.
  • Not databound DataGridView not affected at all.

Current attempt is to dispose only self created internal components. But it has many question too… Dispose on: clear, remove, change?

And the main one (example below is very simplified synthetic and applies to all disposable DataGridView components):

var dataGridView1 = new DataGridView();
dataGridView1.AutoGenerateColumns = false;

// we explicitly create new column
var colmn = new DataGridViewColumn() { Name = "Clmn", HeaderText = "Clmn" };
dataGridView1.Columns.Add(colmn);
// we not dispose colmn here because it's external element
dataGridView1.Columns.Clear();
// we need to dispose it manually
colmn.Dispose();

// new column will be internally created
dataGridView1.Columns.Add("Clmn", "Clmn");
// we can safely dispose it on clear?
dataGridView1.Columns.Clear();

// new column will be internally created
dataGridView1.Columns.Add("Clmn", "Clmn");
// user cash it somehow
colmn = dataGridView1.Columns[0];
// we dispose it here because it's our internal column
dataGridView1.Columns.Clear();
// user want to add it back but colmn already disposed...
dataGridView1.Columns.Add(colmn);

At the moment, I see only one solution - to add a public property like DisposeInternalComponents with default to false not to break current implementations. What do you think? P.s. during investigation I found some small bug and the ability to improve performance - I will try to create a PRs…

/cc @dreddy-work @RussKie

2reactions
kirsan31commented, Jan 17, 2023

@elachlan

are you able to summarize what is left to do for this issue to be resolved?

Most part of the work is already done. Slightly edited my last post:

So we have three problems with dispose not to be called:

  1. Slow down due to empty finalizers on all elements. Completed. For us this is the main problem (and I think that for all too, they just don’t realize it😁).
  2. If element have it’s own ContextMenuStrip - will lead to memory leak. Can be solved by user with setting ContextMenuStrip property to null before each remove/replace of this element. And yes, in some cases this is the pain.
  3. DataGridViewColumn and DataGridViewHeaderCell in some cases really need to be disposed. Can’t say anything about Site logic 😦 Here some details.
Read more comments on GitHub >

github_iconTop Results From Across the Web

Why does components.Dispose() not call DataGridView. ...
I encountered this error whenever components.dispose() is called in a windows form with DataGridView. The following exception occured in the ...
Read more >
BindingList<T>, DataGridView and DataGridViewRow. ...
Hi, I have BindingList<T> that is bound to DataGridView, via BindingListView<T> like: ... Every number of items, the list is cleared, with.
Read more >
Public DataGridView is Disposed By a Class and Not ...
I am copying a DataGridView on a visible UserControl to a Public DataGridView within a Class, which eventually is disposed.
Read more >
DataGridViewCell.Dispose Method (System.Windows.Forms)
The Dispose method leaves the DataGridViewCell in an unusable state. After calling Dispose, you must release all references to the DataGridViewCell so the ......
Read more >
Solved: My C# application hangs on closing main form at ...
The full query of 24000 records takes several minutes to close the form. It always hangs at components.Dispose() in the form Dispose method....
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