How to make .NET Garbage Collection less frequent?

2020-07-09 03:44发布

问题:

I have an application that procesess large number of small objects, e.g. 2000 messages per second. One message is roughly 100 bytes, maybe less. The application ran for 6 and a half hours under load and during that time it had 264 416 0th gen collections, 166 699 1st gen and 69 608 2nd gen. This is 11.6, 7.3 and 3 collections per second respectively.

The question is how to make garbage collection less frequent?

UPD: Application is a server receiving messages from WCF, pughing them though several processing modules and saving them to database.

I was under impression that GC should adapt and increase generation size after some time but this is obviousely not the case.

UPD 2: as suggested in leppie's answer GC in server mode indeed makes 10 times less collections. Also it appears (as Richter describes it) that frequent collections are not a bad thing.

回答1:

You will get about 10 times less GC's if you enable gcServer="true" in the app.config. But do note, this does not improve performance, and you will have likely have increased latency in your application if it is a desktop application.

Here is app.config setting:

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


回答2:

What makes you think this is impacting you? In particular, gen-0 collections are very, very cheap - and to be encouraged.

I would look more at ""What might cause some of these requests to escape gen-0 into gen-1; am I clinging onto any object unnecessarily, for example via an event?".

Of course, another thing to look at is: are there any places you can avoid creating unnecessary objects, for example:

  • are you doing string concatenation in a loop that could be StringBuilder instead?
  • any moderate-to-large collections that could be initialized with the correct length to avoid reallocations?
  • any scratch-buffers that could be reused? for example, do you do a lot of encoding work that uses a byte[] briefly in a method, where that byte[] could be passed in as a scratch area, or grabbed from a pool?
  • any other things that could be cached and re-used - for example, a new Regex("some literal") created inside a method, that could be made into a static field, plus compiled for performance
  • any intensive string parsing that could use interning? (not necessarily the inbuilt interner though)


回答3:

The number of gen #0 collections is about right. Gen #1 and #2 are too high, these objects live too long. Maybe you stick them in a queue and they sit there for a while before getting processed. Otherwise a sign that you are close to saturation. Short from getting them processed quicker, pooling the buffers might help.



回答4:

Have you considered using value types instead of reference types? It could be a good option if the 'objects' are transient and only needed during processing. Value types (structs) are allocated on the stack, and thus does not need collection (like class instances).



回答5:

Your problem is not the Garbage Collector, but that you have too many objects. If your process is serial and you don't need to have all these objects in memory at the same time, try to reuse instead of create and destory. If performance it's your goal, use other type of strucures to store data, such as arrays, memory stream or other, but not collections of objects.



回答6:

Maybe you should consider using object pool or flyweights. More reusable objects often lead to less garbage and make GC less frequent.