none
Excessive number of gen0 collections RRS feed

  • Question

  • Hi,

    I am running the code below in the UI thread of Console app using .NET4 and Windows 7.

     

                        do
                        {
                            string url = String.Format("{0}", "some text");
                            // Thread.Sleep(10);
                        }
                        while (true);
    


    I see counter "# Gen 0 Collections" increasing by hundreds per second using perfmon. Gen1 and Gen2 collections stay close to zero.

    If I uncomment the Thread.Sleep statement above then Gen0 collections stay close to zero too as expected.

    Can you explain me what is the relationship between this Sleep statement and the number of Gen0 collections that get executed?

     

    Thank you!

     

     


    Martin Kulov
    www.kulov.net

    Microsoft Regional Director
    VS ALM MVP, MCT, MCSD, MCPD, INETA Speaker
    Thursday, November 24, 2011 12:48 AM

Answers

  • Let me put my opinion. In my i3 machine, I ran the while loop without Sleep. The results are (Apprx)

    Number of Strings created per second: 3000000 (3 Million)
    Number of Gen0 collection per second: 100 (so Gen0 occurs when there are more than 30000 objects in memory)

    Then I added Sleep(1). Te Appx results are

    Number of Strings created per second: 300
    Number of Gen0 collection per second: 0.1 (I calculated it as (100*300)/3000000).

    With this result, when Sleep(1) is there, only 300 objects are created per second and there is enough memory on heap and GC is happy. After 10 seconds, the number of objects in memory is 30000 and GC will see that there is no enough memory and hence Gen0 will occur. Since all 30K objects are candidates for garbage collection, all will be collected. Result is zero objects on heap. So, again for 10 seconds GC will keep quite. It means, Gen0 collection rate decreased from 100 per second to 0.1 per second.


    Please mark this post as answer if it solved your problem. Happy Programming!
    • Proposed as answer by Paul Zhou Tuesday, December 6, 2011 9:03 AM
    • Marked as answer by Paul Zhou Tuesday, December 6, 2011 9:07 AM
    Monday, November 28, 2011 12:19 PM

All replies

  • Since you haven't had a response in almost 5 hours, I guess no guru's have appeared on scene yet.  I'll bump this up with this (I may very well be wrong):

    Gen1 and 2 shouldn't go up because there's no need to move the abandoned strings up, but gen0 keeps growing because the thread keeps working, so even if these strings were to go up a generation they can't.  I am guessing that the .Net's Thread.Sleep() method has some sugar for the Garbage Collector and before it goes to sleep it gives the GC an opportunity do some cleaning, which is why you see gen0 dropping.

    To test if Thread.Sleep() endorses GC's undercover activities, exchange it with the WinAPI call Sleep().  I would imagine that the behavior changes.


    Jose R. MCP

    • Edited by webJose Thursday, November 24, 2011 5:38 AM
    Thursday, November 24, 2011 5:37 AM
  • When Thread.Sleep is commented, do-while loop runs at higher rate which is more than 3 Million loops per second. It means, 3 million string objects are generated per second. And each object is a candidate for garbage collection after each loop. So, may be because of this Gen0 runs at faster rate. Also, all objects are ready to be garbage collected Gen0 collects all and hence, no obct is moved to gen1 & gen2 so, they will not run.

    When Thread.Sleep is uncommented, the rate at which the loop runs is less. This means less number of string objects are create and hence Gen0 also runs at slower rate.


    Please mark this post as answer if it solved your problem. Happy Programming!
    Thursday, November 24, 2011 5:39 AM
  • Generally speaking, GC would collect unreachable objects when allocated heap size of Gen 0 is full. GC works as that if we do not force to call GC.Collect method. As we know, CPU is a component that computes in a very high speed. if you do not keep a Thread.Sleep method to slow down the execution, the loop will create many objects in a short time. That is why you see "# Gen 0 Collections" increasing by hundreds per second using perfmon. Gen1 and Gen2 collections stay close to zero.
    Paul Zhou [MSFT]
    MSDN Community Support | Feedback to us
    Thursday, November 24, 2011 7:26 AM
  • Hi guys,

    I agree with you that with no Sleep() statement there will be much more objects created and Gen0 collections will go high as observed now. I see more than 300 Gen0 per second in this scenario.

    However this is not the issue I need help with.

    I would expect that adding Sleep(1) statement will reduce the number of Gen0 collections a bit. However when I add Sleep(1) I see about *1* Gen0 collection for a period of about 12 seconds.

    I think this is highly non proportional value. It actually makes sense in high performing code to add Sleep(1) in order to avoid hundreds of Gen0 collections to incur.  I could live with Sleep(1) performance hit where saving % in GC time spent.

    Am I missing something?

    Thanks!


    Martin Kulov
    www.kulov.net

    Microsoft Regional Director
    VS ALM MVP, MCT, MCSD, MCPD, INETA Speaker
    Thursday, November 24, 2011 9:12 AM
  • If using Sleep(1) is not satisfactory enough, I think you can force to call GC.collect(0). But I think also there will be performance hit. You can try it.

    For example:

    int count=0;

     do

    {
    	count++;
          string url = String.Format("{0}", "some text");
          // Thread.Sleep(10);
    	if(count%20==0)
    	GC.Collect(0);
    }
    while (true);
    

     


    Paul Zhou [MSFT]
    MSDN Community Support | Feedback to us
    Monday, November 28, 2011 5:30 AM
  • Hi Paul,

    My problem is not how to make GC work faster or to try to workaround when it is invoked.

     

    My question is WHY adding Thread.Sleep(1) has such huge impact over the performance of GC collections being generated?

     

    Thank you!


    Martin Kulov
    www.kulov.net

    Microsoft Regional Director
    VS ALM MVP, MCT, MCSD, MCPD, INETA Speaker
    Monday, November 28, 2011 11:45 AM
  • Let me put my opinion. In my i3 machine, I ran the while loop without Sleep. The results are (Apprx)

    Number of Strings created per second: 3000000 (3 Million)
    Number of Gen0 collection per second: 100 (so Gen0 occurs when there are more than 30000 objects in memory)

    Then I added Sleep(1). Te Appx results are

    Number of Strings created per second: 300
    Number of Gen0 collection per second: 0.1 (I calculated it as (100*300)/3000000).

    With this result, when Sleep(1) is there, only 300 objects are created per second and there is enough memory on heap and GC is happy. After 10 seconds, the number of objects in memory is 30000 and GC will see that there is no enough memory and hence Gen0 will occur. Since all 30K objects are candidates for garbage collection, all will be collected. Result is zero objects on heap. So, again for 10 seconds GC will keep quite. It means, Gen0 collection rate decreased from 100 per second to 0.1 per second.


    Please mark this post as answer if it solved your problem. Happy Programming!
    • Proposed as answer by Paul Zhou Tuesday, December 6, 2011 9:03 AM
    • Marked as answer by Paul Zhou Tuesday, December 6, 2011 9:07 AM
    Monday, November 28, 2011 12:19 PM