Hi
I'm trying to understand some memory problems with my app and I need a basic understanding of how wingrid manages memory.
I have a button which executes a SQL query and returns a DataSet. The DataSet obviously owns an amount of memory
I then bind the DS to the grid using:
ultraGrid1.SetDataBinding( null, null ); ultraGrid1.SetDataBinding( oDS, null );
Q1: Does wingrid copy all of the data from the DataSet into the grid? Is my original DS unchanged?
Q2: If I press the button a 2nd time to repeat I will get a 2nd DataSet. Is my original DS still in memory? Does it go out of memory when ultraGrid1.SetDataBinding( null, null ); is called?
If I look at the app using Task Manager the memory just keeps going up until I get an out of memory exception
Thanks
gstanbury said:Q1: Does wingrid copy all of the data from the DataSet into the grid? Is my original DS unchanged?
No, and yes. The grid doesn'y create any kind of copy of the data, although the grid does create structures of it's own that will mirror the data source. For example, the grid will create bands and columns to represent the tables and fields in the data source. For the data itself, the grid will often request the data value of a particular field and put that data into a UIElement to display as a string or image, etc.
The Datasource is not change in any way at this point (assuming you haven't changed any of the cells in the grid). But the DotNet framework will create a BindingManager to help communicate between data source and the grid and maintain the current position.
gstanbury said:Q2: If I press the button a 2nd time to repeat I will get a 2nd DataSet. Is my original DS still in memory? Does it go out of memory when ultraGrid1.SetDataBinding( null, null ); is called?
Pressing this button a second time will disconnect the grid from the DataSet and then reconnect it. No new DataSet is created (since you are still referencing the same oDS variable). Your original DataSet is still in memory (assuming nothing in your other code outside of this button disposed it).
If the memory is increasing every time you do this, then it's possible it's a memory leak in the grid, or the BindingManager or in some other part of your code like one of the grid's event handlers.
Thanbks for your quick reply.
The DataSet is new each time.
So, when I call:
DataSet oDS = GetMeSomeData()
ultraGrid1.SetDataBinding( null, null )
ultraGrid1.SetDataBinding( oDS, null )
is my original DataSet still in existence?
I'm not familiar with the BindingManager (even though I have used Wingrid for years). Is this something that I have to get rid of?
Thanks for your help. In my application I can potentially have a grid with 200,00 rows with 200 columns. After filling the grid once the Task Manager shows a working set size of 500M. If I re-run the query, the memory usage never goes down but ends up at 900M. If I do it again it goes up to 1.2G. After a few more goes it bombs with an out of memory exception. My code basically looks like yours.
I used to do GC.Collect & GC.WaitForPendingFinalizers between each refresh, but with Windows 7, as soon as GC.WaitForPendingFinalizers is called alled of the grid hidden columns are briefly unhidden, and then re-hidden when the call completes. I took it out because it scares the users. It doesn't make any difference to the memory usage if I leave it in.
If I fetch a smaller amount of data the memory doesn't go down. It's only when I close the form that the memory seems to be released.
Should I be looking in places like InitializeRow and IntialiseLayout for problems?
The app has a single wingrid whose contents vary depending on a toolbar button. e.g. the same grid is used to display a list of equipment, jobs, spare parts etc. The grid layout is different for each.
oLayout = new UltraGridLayout(); oLayout.CopyFrom( ultraGrid1.DisplayLayout );
oDS = GetSomeData();
ultraGrid1.SetDataBinding( null, null );
ultraGrid1.SetDataBinding( oDS, null );
Then I call:
ultraGrid1.DisplayLayout.CopyFrom( oLayout );
Could that cause the data to be held on to?
Any chance of a copy of that test project with 14.1?
Hi,
Thank you for the replies.
I have attached a 14.1 version of my test sample, I have also modified it with the code that copies the layout.
Even after adding the layout code, it still works properly and memory usage doesn’t increase after changing the data source 100 times. Note that the GC.WaitForPendingFinalizers() and GC.Collect() calls are to reduce the wait for the garbage collector. The application should use the same memory without them once the garbage collector decides to collect the memory, but that can happen after some time.
If the memory increases for you, then something must be still referencing the old data source and thus the garbage collector can’t free that memory. Please modify my sample so it reproduces this issue and I will be glad to investigate it further.
I am looking forward to hearing from you.
Hi Dimitar
Thanks very much for the sample. I will keep playing with this until I can reproduce the behaviour that I am seeing with my app. If I can then I will get back to you. Apart from using lots of caches (generally HashTables) and having many different screens and cached layouts/DataSets, in principle the sample you have sent should allow me to do that.
I'm fairly certain that it relates to Excel filtering in some way. If I repeat the same search multiple times then I end up with an arbitrary number of DataSets left in memory and they are always being held there because of FilterUI objects
Thanks for your help
Hello,
I am just checking about the progress of this issue. Have you been able to isolate the issue in a separate sample? Let me know if you need any further assistance on this issue.
Thank you for using Infragistics Components.
Well, you should not have to do this. If the FilterUI is rooting column object in the previous grid when you attach it to a new grid, then something is wrong.
But if destroying the FilterUI and creating a new one helps, it seems like a viable workaround.
Hi Mike
A form-level variable means that in MainForm.cs I had:
private Infragistics.Win.SupportDialogs.FilterUIProvider.UltraGridFilterUIProvider ultraGridFilterUIProvider1;
Inside InitialiseComponents there was:
...
this.ultraGridFilterUIProvider1 = new Infragistics.Win.SupportDialogs.FilterUIProvider.UltraGridFilterUIProvider(this.components);
this.ultraGrid1.DisplayLayout.Override.FilterUIProvider = this.ultraGridFilterUIProvider1;
This code would have been put there when the form was first created several years ago.
As soon as I deleted that code and replaced it with the following inside the toolclick handler, the major problem went away:
Infragistics.Win.SupportDialogs.FilterUIProvider.UltraGridFilterUIProvider oColFilterUI; oColFilterUI = (Infragistics.Win.SupportDialogs.FilterUIProvider.UltraGridFilterUIProvider)ultraGrid1.DisplayLayout.Override.FilterUIProvider; if (null != oColFilterUI) { oColFilterUI.Dispose(); } ultraGrid1.DisplayLayout.Override.FilterUIProvider = null;
oColFilterUI = new Infragistics.Win.SupportDialogs.FilterUIProvider.UltraGridFilterUIProvider(); ultraGrid1.DisplayLayout.Override.FilterUIProvider = oColFilterUI;
The variable oColFilterUI is now method-level, rather than form-level.
A simple test harness of the first example shows that many UltraGidColumn objects are held in memory, whereas the 2nd does not.
One of my questions was "is it safe to call Dispose on oColFilterUI in the tool click as I am doing above?"
Now I can refresh the grid as many times as I like, but as soon as I type anything in a column filter the memory leak comes back. UltraGridColumn objects are being held in memory. I'm still trying to make a test harness to show that
I have a memory profiler, so that's no problem. If your sample demonstrates that the memory usage keep increasing or certain object references are increasing each time you perform the operation, we could duplicate that.
What do you mean by "the FuilterUIProvider is a form-level variable." As opposed to what? Are you placing the component on the form? Or are you creating it in such a way that it gets disposed along with the grid?
Thanks Mike
I'm trying to reproduce this in a test project. I can reproduce the problem with UltraGRidColumns being held in memory if the FuilterUIProvider is a form-level variable, but you need a memory profiler to see the results.
I can't reproduce the problem that I see whenever column filtering is used. My app is pretty consistent. By making the FilterUIProvider not a form-level object I can refresh the screen as many times as I like. As soon as I type "X" in a column filter I can only refresh it twice.
I will keep trying.