Page 1 of 1

Profiling a ASP.Net app

Posted: Thu May 11, 2006 8:37 pm
by SG
I am investigating a memory leak in our app(website). We perdiocially see a "System.OutOfMemory Exception". I have set up teh profiler on my web server and am using the "Profile ASP.Net" option.I want to use this whole setup as part of my stress and perf. tests. I am new to this tool, and trying to figure out teh best way to use this - Should I take a snapshot first, launch my stress test and then take a snapshop in the end? I woudl probalby need to stop the profiler during my stress test, sicne the profiler app itself will impact my perf. counters (which i need to collect).

Posted: Fri May 12, 2006 2:01 pm
by Andreas Suurkuusk

It is not possible to stop the profiler and then reattach it to the same process. If possible, I recommend that you start the profiler, collect a snapshot, run your stress tests (without stopping the profiler) and collect a second snapshot. If you need to collect performance data during the stress-test, I think that you will have run the stress-test separately as well (without using the profiler), since the profiler does affect the performance of the profiled process.

The next version of the profiler will include an attach-to feature. This feature will allow you to collect a snapshot before and after the stress-tests, without affecting the tests.

Posted: Fri May 12, 2006 9:23 pm
by SG
Thanks! I decided to go that route as well. How important is it to know which instances need to be garbage collected? We dont have much knowledge of the app itself (so not familiar with all the classes etc). Are there any useful pointers on how to go about investigation a memory leak without having this kind of knowledge? A related question to the memory leak issue we are seeing - We get System.OutOfMEmory exception, but I noticed during a stress test run, that even after getting this exception, the load test continues just fine! If the server is indeed out of memory, how can it conitue to process requests? It almost seems like the situation is correcting itself...Also do you always need two snapshots to detect a memory leak? What if I take a single snapshop at the end of the stress test and analyze that one? Is that possible?
This time around, I kicked off my stress test, took a snapshop within a few minutes and let the profiler and my stress test run. I wil then take a secodn snapshot after about 20 hours or so. Will this help?

Would also like to ask a few more questions for the Dispose Info view: Is this information only relevant to classes that implement IDisposable? I see huge numbers in this column, and was reading through your help file to understand the significance of this. i am not very clear on this, could you please explain? How does "Dispose" apply to a class that does not implement any sort of dispose method?

wanted to add on to my previous post....

Posted: Mon May 15, 2006 1:17 am
by SG
but got an error..

to clarify my previous post - i am seeing huge numbers in the total undisposed column. what is the significance of this column? Thanks!

Posted: Mon May 15, 2006 6:41 pm
by Andreas Suurkuusk

If you don't have any knowledge about which instances should be garbage collected, I suggest that you start by looking at classes that contain a lot of instances, or use a lot of memory. By investigating the class root paths and allocation call stacks under "Class details" view you should be able to get some information on how the instances are used and whether they should have been GCed. It is also good to look for classes which contain disposed instances, since that might indicate a memory leak. When an instance is disposed, it usually means that it should no longer be used and that it should become eligible for garbage collection.

It is not necessary to collect two snapshots in order to detect a memory leak, but it makes it easier. By comparing snapshots, you can locate classes and call stacks whose instance counts are increasing, and thus may be part of a memory leak.

An instance is classified as undisposed if it's an instance of a disposable class (i.e. a class that directly or indirectly implements IDisposable), and it has been GCed or finalized before it has been disposed. Undisposed instances do not indicate a memory leak, but they might cause bad memory utilization and potentially memory leaks on other classes. E.g. consider a Dispose method in one class that calls the Dispose method on a second class. If the Dispose method in the second class removes itself from a global event handler, then you will have a memory leak if this Dispose method is not called. Consequently, if you fail to dispose an instance of the first class, this instance might get GCed and counted as an undisposed instance. However, the instance of the second class will never be disposed and never GCed.

If you have classes that have undisposed instances, it is recommended that you investigate why they're are undisposed, and whether it has any negative side-effects.

Are you sure that your ASP.NET process keeps running after the OutOfMemoryException? IIS will recycle the ASP.NET process if it uses to much memory or if it crashed. However, it is possible for a process to keep running, even after an OutOfMemoryException. Maybe the OutOfMemoryException was caused by a very big allocation. Subsequent allocations may request much less memory and therefore not cause an aditional OutOfMemoryException.

Posted: Mon May 15, 2006 8:01 pm
by SG
I took a snapshot a few minutes after starting my stress tests, and over a period of about 25 hours, have taken several snapshots. I have compared the first snapshot with several later ones - the general observations are: Disposed Total instances is geneally zero for all classes, but the Undisposed Total instances is massive! A couple of classes actually have Undisposed Total instances in the order of millions!

This might be a .Net q - but how can a disposable class be GC'ed if it has not been disposed (which is what I understand from your previous reply...)? Thanks!

Would like to add one more q - With time, I am seeing that the Total Undisposed instances is just growing! Just to make sure I am understanding this correctly - does this number indicate the instances of those classes (that implement the idisposable interface) that have not been GC'ed? I have also found out that our code is not explictly calling dispose on these objects...would this account for the high number? Thanks!

Posted: Tue May 16, 2006 5:46 pm
by Andreas Suurkuusk

An instance can be garbage collected as soon as it is no longer reachable from any root. This can happen even if you don't explicitly dispose the instance. The main reason for disposing an instance is that you make sure that unmanaged resources are released as soon as possible. The garbage collection is non-deterministic, so even if an instance is unreachable, it will take an undetermined amount of time before it is actually collected (or finalized).

No, the Total undisposed instances count does not indicate instances that have not been GCed. It's the other way around, they have been GCed, without being disposed.

If you have instances of disposable classes it is recommended that you call Dispose on them (when you know that they should no longer be used).

Posted: Tue May 16, 2006 11:45 pm
by SG
Thanks! It does look we are not calling dispose on the objects of those classes with really high (in the order of millions) total undisposed instances. I was trying to further see when these objects are created using the instance details, call stack etc...i see the age for one of the undisposed instance as 1,426,578. what does this mean? My understanding of age was that it indicated the number of times an instance survived a GC....

Posted: Wed May 17, 2006 2:21 pm
by Andreas Suurkuusk

You cannot (normally) look at an undisposed instance using the instance details view. The instance details view only include live instances, and undisposed instances are almost never "alive"*. The thing you can investigate about undisposed instances, is the allocation call stacks of the instances. You do this by selecting "Delta undisposed instances" in the "Sort stacks by" drop-down list in the Class details view.

*Since an instance is considered to be undisposed when its finalizer is called, it is theoretically possible that an undisposed is "alive". E.g. the finalizer might still be running when the snapshot is collected, or the instance is resurrected in the finalizer.

Posted: Wed May 17, 2006 8:58 pm
by SG
Yes, sorry was doing what you called out below. I am looking at the delta undisposed instances. However, I am still not clear on what age signifies?

Posted: Fri May 19, 2006 9:06 pm
by Andreas Suurkuusk

As you asked in one of your previous posts, the age of an instance indicates how many garbage collections the instance has survived. If you have an instance that has an age of 1,426,578, it means that it has survived 1,426,578 garbage collections (which is quite a lot).