GC.Collect() will more likely hurt your performance

A friend called me today to ask me a question about a problem he’s experiencing with an asp.net application. The application is very slow and the CPU is very high. I asked him to check the amount of CPU time the application spends in the GC (MS recommends this to be at 30% at the peak times):

HINT   If the .NET CLR Memory: % Time in GC performance counter indicates that your application is spending an average of more than 30% of its time in GC you should take a closer look at your allocation profile.

It was about 90% most of the time. After inspecting the code a bit he noticed that he calls the GC.Collect() on every hit to the server, the reason was that he has some classes that use com components and the com components are being released only when the GC runs. The solution was to use the IDispose pattern on those managed classes and manually releasing the com components instead of calling GC.Collect()

Comments (2)

  1. Addy Santo says:

    Hi there!

    First of all – you are 100% correct about GC.Collect. One of the reasons it is so painful is that it forces a full collection (all generations) which is MUCH slower than the usual gen-0 cleanup. There is an overload for Collect which allows specifying how many generations should be included, but it wouldn’t help in the scenario you described since the COM objects could potentially be in any generation (though chances are they usually wouldn’t make it past gen-1).

    The IDispose pattern will certainly work, but it is a flawed solution in that it forces you to wrap any COM objects you use in managed code (in order to implement Dispose). You can’t just call the existing COM objects from within pages without investing a fair amount of effort, especially if you have many COM objects which need to be released. Also, IDisposable is a developer coding convention, so if developers forget to manually release the resources you will still be leaking.

    The best solution I know is to use the ASPCOMPAT page directive, which forces the ASP.NET engine to more closely mimic the way ASP interacts with COM+. Your scenario is one of the main reasons that ASPCOMPAT was added in beta2 (or was it only in the release? wow it’s been awhile) – the early adopters tried to leverage their existing COM investments and it was killing the servers.

    Hope that helps!

  2. Natty Gur says:

    In addition to any post,

    I saw that using System.Runtime.InteropServices.Marshal.ReleaseComObject() helps to release com objects. Without using ReleaseComObject Com counter reference wont decrement and the com object wont release.