Page 1 of 1

Bound DataGrid leaking DataRow objects using DataSet ReadXml

Posted: Mon Aug 15, 2005 10:57 pm
by rocketstream
I know the subject sounds like a tongue teaser, but I can't get my arms around this...

I've been chasing this "situation" down now for 3 days. Here's the issue, when I create a DataSet using ReadXml, it properly generates a table that I bind to a grid. In my application, this information updates fairly frequently, so I update the dataset, thereby updating the grid information. It's a static 22 rows of data across 5 columns - not a lot of data.

I noticed a memory creep problem that caused me to go through enormous gyrations in determining the problem. In my application, with the code below, DataRow objects are never released - they continue to grow in instance count and memory usage and never release.

Ironically, if I tear down the DataSet and create a new one, the DataRow object issue goes away, and is then replaced by a WeakReference and BindingContext.HashKey issue that parallels the original.

Apparently, the rows are somewhat still connected to the underlying DataView. I know this because after trying to Dispose the 0 index table, I eventually tried to Dispose the DefaultView which did the trick - no memory loss whatsoever - of course, then nothing displays in the grid! LOL.

By all accounts, it would seem this is fairly straightforward, and should run without memory creep.

Here's the snippet below that causes the problem. Any insight greatly appreciated. "xml" is a string that contains a properly formatted data set without a schema - it works great, except for the DataRow (and btw, also a parallel DataError object) remaining in memory forever and never getting cleaned up by the GC.

using (sr = new StringReader(xml))
{

// clear away the prior tables and rows, or it will append rows
ds.Clear();

// read the xml string via the StringReader into the dataset
ds.ReadXml(sr);

// close the stringreader
sr.Close();

// assign table as datasource to grid
myGrid.DataSource = ds.Tables[0];
}

BTW, if I choose to bind the DataSource only once, no difference.
If I clear the bindings in the grid before, no difference.
If I make another DataSet instance, clearing the first, then the WeakReference problem occurs and never releases.

Maybe the grid is supposed to work this way. Last night I ran an intensive demo and it had creeped up to 60MB of just un-garbage-collected DataRow objects. If I go through the profiler I can find where DataRow objects, that are null, are remaining in the ArrayList under the DataView object contained by the DataTable object.

I hope someone can shed some light on this.

Thanks.
Scott

Posted: Wed Aug 17, 2005 7:06 pm
by Andreas Suurkuusk
I took a look at the problem you have with DataRows and DataErrors not being properly garbage collected. I have not looked at the problem with WeakReferences when replacing the DataSet.

Anyway. The problem is that the DataView keeps a reference to the row that is currently being edited. When this row is removed from the table, the DataView still keeps a reference to the row.

You can solve you memory leak problem by cancelling the editing of the row, before you clear the table. E.g. in your code, replace ds.Clear() with:

Code: Select all

// clear away the prior tables and rows, or it will append rows 
if( ds.Tables.Count > 0 )
{
  foreach( DataRowView rowView in ds.Tables[0].DefaultView )
    rowView.CancelEdit();
  ds.Clear(); 
}

Of course it would be better to look up the row that is being edited, and only cancel editing on that one.


I hope this helps you solve your memory problem.