GC doesn't work in my ASP.NET application

  • Thread starter Sherif ElMetainy
  • Start date
S

Sherif ElMetainy

Hello

I have an ASP.NET application that just keeps leaking memory. The memory
used by the application just keeps growing until the ASP.NET worker process
is recycled when the memory limit is reached. I looked at the performance
data and here is what I found:

ASP.NET Requests Total : 28462 (Keeps increasing)
ASP.NET Requests/Sec: 2 (5 in peak hours)
Gen 0 Collections : 157 (This is really bizzare that after more that 28K
requests)
Gen 1 Collections: 76
Gen 2 Collections: 10
Induced GC: 3 (My code doesn't have a call to GC.Collect anywhere, and I am
not using 3rd party components that may do that)
#Bytes in all heaps: 237MB (Keeps increasing)
Gen 0 Heap Size: 98MB (keeps increasing)
Gen 1 Heap Size: 7MB
Gen 2 HeapSize: 130 MB
Large object Heap Size: 1MB
% of time in GC: 0.032

My question is why do I have so few garbage collections? Why is Gen 0 so
big? I read that it is typically the size of the processor's cache, but
98MB? Why aren't they promoted to gen 1 or gen 2?

My application is running with the following configuration:

Compaq ProLiant ML370 G3
Quad Intel Xeon 2.8GHz Processors
Windows 2000 Server (Service Pack 4)
2GB RAM
Microsoft .NET Framework 1.1 (Without Service Pack 1. Is this the reason?)

Best regards,
Sherif
 
O

Oleg Ogurok

Check your static (Shared in VB) fields in all classes that have them.
Static class variables remain in memory until the worker process is
recycled.

-Oleg.
 
S

Sherif ElMetainy

Hello

Thanks for the reply. I understand that static variable will survive garbage
collections and would be promoted to gen 1 or gen 2. But this doesn't
happen. Gen 0 heap size is very large, and the number of Garbage collections
is very low.

Best regards,
Sherif
 
M

Michael Pearson

If I recall, GC only happens during "idle" time. Maybe the machine in
question is getting hammered?

Michael
 
D

David Browne

Michael Pearson said:
If I recall, GC only happens during "idle" time. Maybe the machine in
question is getting hammered?

Not true. In fact it is quite the opposite. GC is triggered by memory
allocation requests when the memory passes certian internal thresholds.
When a memory allocation request is pending, the app is never "idle".

As a diagnostic tool, I would force a complete GC after each request and see
what happens. I would also code an admin page with a "Force GC" button on
it to see what happens.

David
 
S

Shawn B.

I've had something similar in the past, the cause of our problems is because
a managed object that contains a reference to an unmanaged resource, that
requires Dispose() to be called before it'll release it, was not having
Dispose() / Close() called in order to release it and it brought our entire
datacenter and farm to a screetching halt. Just so you know, these objects
in particular I speak of will never release their unmanaged resources even
during finalize/collect unless Dispose() was called.

Another source could be if you are not calling
"Marshal.ReleaseComObject(myComObject)" because they won't be released
otherwise.

I'm out of ideas otherwise.

Thanks,
_Shawn
 
S

Shawn B.

Try

GC.WaitForPendingFinalizers();
GC.Collect();

at certain points to see if it makes a difference, temporarily as a
debugging tool, not as a solution.


Thanks,
Shawn
 
S

Sherif ElMetainy

Hello

I already did that. This was the first thing that came to my mine.
GC.Collect() call in the EndRequest method. The result was that Gen 0 Heap
size was down to 1MB but the time spent in GC was 99.5% and CPU consumption
went up, and my application was slow. I would rather have 2-3 process
recycles all day than having such a bad performance

Best regards,
Sherif
 
S

Sherif ElMetainy

Hello All

Thanks to everyone who replied. I found a bug in my code that caused some
allocated objects to be referenced by static variables. Fixing it solved the
problem. But I still wander why were these leaked objects not promoted to
Gen 1 or Gen 2? Why did Gen 0 remain big?
Why did I have only 157 Gen 0 Collections after more than 28000 request?

Best regards,
Sherif
 
D

David Browne

Sherif ElMetainy said:
Hello All

Thanks to everyone who replied. I found a bug in my code that caused some
allocated objects to be referenced by static variables. Fixing it solved
the
problem. But I still wander why were these leaked objects not promoted to
Gen 1 or Gen 2? Why did Gen 0 remain big?
Why did I have only 157 Gen 0 Collections after more than 28000 request?

I think because the GC's weren't freeing much memory, the GC heruistics
concluded that your app needed more and more memory and so it kept
increasing its memory targets and thus running GC less and less frequently.

If you look at those 157 Gen 0 GC's I imagine you would see something like

Gen 0 GC Gen 0 Size Before(MB) Gen 0 Size After(MB)
----------------------------------------------------------------------
1 .1 .1
1 .1 .1
1 .1 .1
1 .1 .1
1 .1 .1
1 .1 .1
 
D

David Browne

Sherif ElMetainy said:
Hello All

Thanks to everyone who replied. I found a bug in my code that caused some
allocated objects to be referenced by static variables. Fixing it solved
the
problem. But I still wander why were these leaked objects not promoted to
Gen 1 or Gen 2? Why did Gen 0 remain big?
Why did I have only 157 Gen 0 Collections after more than 28000 request?

oops


I think because the GC's weren't freeing much memory, the GC heruistics
concluded that your app needed more and more memory and so it kept
increasing its memory targets and thus running GC less and less frequently.

If you look at those 157 Gen 0 GC's I imagine you would see something like

Gen 0 GC Gen 0 Size Before(MB) Bytes Promoted to Gen 1
----------------------------------------------------------------
1 .1 .1
2 .2 .2
3 .4 .3
4 1.0 .9
5 2.0 1.7
6 4.0 3.9
7 8.0 6.9
8 16.0 14.9
....

Each GC was so unsucessful and resulted in so much promoted memory that the
targets for the next GC kept going up, and with a constant rate of object
allocation the frequence of GC went down.


David
 
D

David Browne

Sherif ElMetainy said:
Hello

I already did that. This was the first thing that came to my mine.
GC.Collect() call in the EndRequest method. The result was that Gen 0 Heap
size was down to 1MB but the time spent in GC was 99.5% and CPU
consumption
went up, and my application was slow. I would rather have 2-3 process
recycles all day than having such a bad performance

Of course you would never really run your application with a forced GC after
every page render, but it can help diagnose the problem. But you can only
"see" a memory leak after removing the garbage.

Forcing GC will always clear out Gen 0, promoting reachable objects to Gen
1. What you want to see is whether the total amount of managed memory goes
down.

For an ASP.NET web app with a single user, the app should basically return
to its inital state after each Page is rendered. If memory continues to
climb, then you have a memory leak.

David
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,744
Messages
2,569,484
Members
44,903
Latest member
orderPeak8CBDGummies

Latest Threads

Top