I'm getting my chops busted about memory usage for a DOTNET app that is using ultragrids all over the place. One in particular can get pretty big. Right now I'm testing with close to 30,000 rows. I've tweaked my InitializeRow code to make it as efficient as I think I possibly can, which has saved us some memory. My argument is that we are dealing with a ton of data that gets loaded into memory when the grid gets refreshed and/or populated with data and there's not much we can do. It is what it is. I have 3GB of RAM on my PC and I have no issues with the app. One of our testers has 1GB of RAM and he has a lot of problems running other apps while the DOTNET app is running and using up a lot of memory. Even with 30,000 records in the grid I've never seen the RAM get higher than 600-650 MB for the app. So it seems like it's more of a hardware issue. Anyway ...
So I come here asking you guys to take a look at my InitializeRow code to see if there are any inefficiencies in there that I could improve upon. I'm using a separate class which contains about 8-10 appearance objects that I set up at app load time to set appearances for some rows and cells. That has saved us quite a bit of memory versus the way I did it initially - create appearance objects for each row on the fly. I also am using some check mark images (2k) to display boolean data. I thought these may be increasing memory, but recent testing proves otherwise. Here are some benchmark numbers and my InitializeRow code. Any advice you guys have is much appreciated ...
Oh, and let's leave the LoadOnDemand out of the conversation if we can. We don't necessarily like the way that functions, so we are looking at every possibility of reducing memory usage before we throw in the towel and go that route.
No Images
Images
No Appearances
Initial Load
252 MB
250
242
1st Refresh
425
431
414
2nd Refresh
435
428
343
3rd Refresh
432
422
418
// Set tool tip text for row
string status = e.Row.Cells["STATUS"].Value.ToString();
string fldrKey = e.Row.Cells["FOLDER KEY"].Value.ToString();
e.Row.ToolTipText = "ID: " + fldrKey + ", STATUS: " + status;
// Color code each row based on its status value
switch (status)
{
case "NEW":
e.Row.Appearance = UltraGridAppearances.gridAppearances["Red"];
break;
case "CANCELLED":
e.Row.Appearance = UltraGridAppearances.gridAppearances["Gainsboro"];
case "CLOSED":
e.Row.Appearance = UltraGridAppearances.gridAppearances["White"];
case "IN PROGRESS":
// Color row differently based on whether or not T/S's are assigned
string tsStatus = e.Row.Cells["TRBL SHTR STATUS"].Value.ToString();
if (tsStatus == "RELEASED" || tsStatus == "")
e.Row.Appearance = UltraGridAppearances.gridAppearances["Yellow"];
}
else
e.Row.Appearance = UltraGridAppearances.gridAppearances["Lime"];
case "IN PLANNING":
case "READY FOR WORK":
e.Row.Appearance = UltraGridAppearances.gridAppearances["Orange"];
// Set cell images for cells containing TRUE or FALSE
if (e.Row.IsDataRow)
for (int i = 0; i < e.Row.Cells.Count; i++)
switch (e.Row.Cells[i].Value.ToString().ToUpper())
case "TRUE":
// Make data value transparent so we can still sort on the data in the
// column and have an image present
e.Row.Cells[i].Appearance = UltraGridAppearances.gridAppearances["GreenCheck"];
case "FALSE":
e.Row.Cells[i].Appearance = UltraGridAppearances.gridAppearances["NoImage"];
// Set images for indicator columns
foreach (KeyValuePair<int, string> kvp in _indDict)
// Go through all the indicator columns, check the current cell value
// and set the image accordingly
string colName = kvp.Value;
if (e.Row.Band.Columns.Exists(colName))
// Set column heading caption to the original column name from the proc
e.Row.Band.Columns[colName].Header.ToolTipText = colName;
switch (e.Row.Cells[colName].Value.ToString())
case "1":
e.Row.Cells[colName].Appearance = UltraGridAppearances.gridAppearances["GreenCheck"];
case "2":
// This will be for indicators that need to display a different icon for a NEW state
e.Row.Cells[colName].Appearance = UltraGridAppearances.gridAppearances["RedCheck"];
default:
e.Row.Cells[colName].Appearance = UltraGridAppearances.gridAppearances["NoImage"];
Thnks Mike
ayub said:e.Row.Cells["File"].ButtonAppearance.BorderColor2 = Color.Transparent; in InitializeRow()
e.Row.Cells["File"].ButtonAppearance.BorderColor2 = Color.Transparent;
in InitializeRow()
This is going to force the creation of a cell, so it will use up some memory.
ayub said:using ultraGrid1.DisplayLayout.Bands[0].Columns["DateTime"].Hidden = true;in InitializeLayout()
using ultraGrid1.DisplayLayout.Bands[0].Columns["DateTime"].Hidden = true;
in InitializeLayout()
I can't see why this would cause a problem. If anything, this should gain you memory, since the grid will never have to draw the cells in this column.
Thnks Mike,
Nice tips,
If i am using
in InitializeRow() or using ultraGrid1.DisplayLayout.Bands[0].Columns["DateTime"].Hidden = true;
in InitializeLayout(), is it also a performance hit.
Mike,
Thanks for the heads up on that. It seems to have cut memory usage almost in half for me. We'll see if that keeps the lions at bay ...
One thing I noticed right away that you could improve is the use of cells. The grid tries not to create UltraGridCell objects until they are needed. Sometimes, you have no choice but to create the cell. For example, you need the cell to apply an appearance to it.
But you can get the Value or Text of the cell without creating it.
This:
can be replaced with:
string status = e.Row.GetCellValue("STATUS").ToString();
The GetCellValue and GetCellText methods allow you to get the value or text of the cell without forcing the cell object to be created.
So it seems like you can avoid creating quite a number of cells here and when you multiply that by 30,000 rows, that should give you back a nive chunk of memory.