views:

112

answers:

2

I am using C# 3.5 and the reactive extension supporting TPL in C# version before 4.

My application calls GC.Collect() in several places (yes, I know that I should not manually call this method but please leave this point alone for at least this question). Before I put multithreading implementation in, it works fine. GC.Collect() is called in each of the thread so it is called in a multithreading context.

Then I use the Task to implement multithreading and I found that after the application running for a while and the memory usage increases, the threads stop working properly. I declare "the threads stop working properly" from the scenario that the CPU usage on a multi-core computer drops to single-thread level, rather than fully utilized.

When I attempted to tackle this problem, the only thing I did was to comment out the GC.Collect() call and this change makes the threads working fine. I would like to turn GC.Collect() off unless when I run something big in my application, without GC.Collect(), I will run into OutOfMemory exception. This is the reason I keep the call.

Now could anyone explain why GC.Collect() being called in a multithreading context on a machine using high memory causes multithreading problem? Is there any related theory on this bit? Thank you very much for the answer.

+6  A: 

GC.Collect() performs a full garbage collection which will block all threads. It has an overload GC.Collect(int) that allows you to specify which generations to collect. For example, GC.Collect(0) will only collect the first generation. Not certain that will solve your problem, but worth a shot.

Kirk Woll
What a quick and insightful help. I will have a try. Thank you very much.
Steve
A: 

As Kirk has said, a collection pauses all threads. This might result in some latency during garbage collection.

If you are running your application on a multi-core machine, you might want to try using the Server GC, by making sure that your app.config contains:

<configuration>
 <runtime>
   <gcServer enabled="true"/>
 </runtime>
</configuration>

Also one can enable concurrent GC instead (though I think this is the default for your case, e.g. a desktop app on a multi-core machine, running .NET 3.5):

<configuration>
  <runtime>
    <gcConcurrent enabled="true" />
  </runtime>
</configuration>

You might try ServerGC - it might give pauses as well, but these pauses may be shorter/fewer and it might give a better overall throughput. Your mileage may vary.

andras