views:

105

answers:

2

We have several different projects using ASP.NET and DevExpress ASPxGridView components. Throughout the development of these projects, several techniques on databinding have been used and we're now finding that some of these projects are eating up all the memory on the server.

Originally, we were using a call to a stored procedure and binding a DataSet to the the gridview, but on DX recommendation, modified this to an ObjectDataSource and created and object that ultimately uses a Linq statement against the DB and returns a generic list of objects which is then bound.

Unfortunately, this does not cure the problem at hand. We're still noticing large amounts of memory being eaten up and I'm trying to get to the bottom of this. When running through RedGate memory profiler, I notice that there are lots of strings, RuntimeTypeHandles and instances of my object created everytime we rebind to the grid.

The DataBind is done on page load, and the grid uses postbacks on sorting, but this is causing MBs of memory to leak on every bind, so I'm wondering what techniques I can use / best practices for managing the objects we have control over? I've implemented IDisposable in the data object, disposing of the linq context and setting any other objects to null, but it doesn't seem to make a difference. I seem to be creating an instance of the data object on every call, and even calling dispose makes no difference.

+2  A: 

Wow, lots of plumbing and moving parts in there.

Is it possible to narrow things down a bit? That is, can you strip stuff off the page and see how it performs?

Forgive this, but when you say 'leaking memory' what do you mean and how do you know? The GC is 'lazy' and won't do anything until there is pressure to do so. This is a good thing but it also means memory may appear to accumulate until a collection is needed, and then you may find it frees a lot up. Memory profilers often look like a saw-tooth for this reason.

How are you storing the grid data to make the paging work? I've seen datasets persisted in viewstate, which means the data goes to the client along with the grid. If you're querying again on post-back page-load you're wasting a lot of space there.

Another common problem is event subscriptions keeping large objects alive longer than they should. I've actually seen code where a datagrid was placed in session state which kept the page alive for as long as the session was. On each post-back this happened again and again until poof. In this case, GC couldn't help us becuase the objects were indeed still 'in-use'.

So try to simplify - turn off sorting, get rid of the 3rd party control, use a smaller data set, etc. Using a memory profiler and something that puts the server under pressure, measure this scenario. If you find no 'leaks' then start adding stuff back to see when it goes haywire.

n8wrl
By leaking memory, I mean new objects that are being created on each subsequent page load, where the previous instance created has not been cleaned up. I'm using Redgate Memory Profiler, I load up the page and take a snapshot as a baseline. I then hit a sort, I see 2 new instances of the data object created, so it shows 3 live instances. Hit another column to sort and I get a 4th instance. We're not storing the grid in the session or viewstate, we're just binding to the grid on page load.
Hammerstein
+1  A: 

You may be returning too much data to your iis server each time. Remember that using standard linq datasource with the devexpress grid, each time you do a callback for sorting, or paging or any other callback, the whole data is loaded in memory and then sorted and paged.

This means that if you are loading a very large amount of data you will easily waste server memory. Think that you may have much users opening the same page and this will load the whole data in memory for each user, and the GC may not have time enough to free all that stuff.

DevExpress provides for this the LinqServerModeDataSource, that does all the paging and sorting in the data server.

If you cannot use that, try to retrieve a smaller set of data by filtering it.

jmservera
The LinqServerModeDataSource though requires a Linq context and a table name, if my object returns the IQueryable straight from Linq, will this allow me to use my data? Or am I stuck trying to work with paging the list I send into the ObjectDataSource? The data on some of our systems, needing to be displayed in a grid, is in the 100,000+ record range so I can certainly understand why memory is disappearing so fas
Hammerstein