At what times is it necessary to force garbage collection in C# for better application performance?

Asked

Viewed 622 times

21

Usually I always have doubts about the use of functions for memory release, in which situations should it be used or should it always be used? And mine really will perform better?

If possible someone could give me an example of its use?

1 answer

28


Never!

Okay, if you have a complete command of how the current GC implementation works, are willing to pay the price if a change occurs and can improve when there is a change, it might be worth doing something about it. That is, only when you know when to force the collection will give you the "right" to do so. In a superficial response on the internet, it will not give you this.

If you can do exhaustive tests, if they have had enough quality and prove that manual collection does not cause loss of performance or at least that these losses do not affect the application, then you can use it. Usually it doesn’t even make up for the work, in most cases there will be loss. In cases where loss is tolerable, manual collection probably will not help.

Current implementation

In the current implementation of . NET calling the collector only makes things worse, I would say in 99.99% of cases. Because it’s generational, it’s going to artificially drive the data of one generation to another, and all you don’t want is for the data to arrive in the last generation, the most difficult to manipulate and cause the problems that people say the garbage collector has, such as long stops, for example.

When you make the collection of a garbage without the "basket" being full there is a waste of resource. The more garbage, the better the GC works, also because it works with copy of the data "survivors". Ideally no surviving data would make the collection much faster. The GC of . NET is one of the best existing on the market and has been carefully designed to bring the best results, it is rare that the programmer is smarter than him.

I’ve seen it said that if you know everything is going fast for Gen 2 (the last one), then it’s not too problematic. Yes, it’s true, but why is this happening? There’s probably a problem of design of the application.

Where it’s safe to use

There is a case where you can use it almost safely. When you go for a performance test and know that the memory will not fill up. You can force it just to help make sure the collector isn’t called inside the test. Still the ideal is to ensure that he was not called before relying on the results. You can instruct him.

Other cases are used to obtain the same effect, prevent a collection from taking place in the middle of something important. But if it’s really important, maybe you shouldn’t use something that can be collected.

Some people try to do that between rendering frame of games to avoid unexpected freezes. This may work in certain circumstances, but it’s usually a bad idea and you don’t usually do this. The current implementation helps avoid long stops, so games are made with . NET without problems. Calling the collection will probably cause more long stops.

Avoiding the creation of waste

What you can do is minimize the use of GC-managed memory by allocating more things on the stack, or create pools memory managed by the application, even if they are in the heap managed, so only desaloca when the programmer wants. But the work this gives, the difficulty to do right, usually does not compensate. If this is really necessary, it is almost always better to use another language. Or at least you can use one pool object standard you now have on . NET.

But it is necessary to be careful, in general the GC does a great job. There is a article showing the extra work it takes to try to manage allocations on your own. And if you do that you risk making a mistake and ending up with a memory leak.

The article shows how the Raymond Chen made a code in C++ that got an excellent performance, but it took a lot of work and the code became complicated and almost unreadable, besides being easy to make a mistake in it. While the C# code performed closely on a port simple of the first version of Raymond, without even "idiomatizing" for C#. With little improvement came even closer.

Note that the C# used was primitive, not had Generics that has gone on to help the performance a lot now. Today the end result could be more favorable to C#. And if I understand correctly the test involves up to the load time of the executable that is clearly worse in C# because of Jitter (now we have the possibility to run without Jitter). And maybe you could get better if you accepted a less readable C# code using advanced techniques.

Manually managing code certainly gets better results than GC-managed code, but in most cases it doesn’t pay off. In many cases the GC will give a better performance than a simpler and naive code with manual management. For all there are exceptions.

References

  • 1

    Great job @bigown, this answer says it all, I’ve been through some very serious problems using GC.Collect without assessing its impact. This response will greatly help the entire software development community.

  • From what I understand about what was exposed here, is that, I never make the GC call manually ? Just, I’ve been researching about memory consumption when using Reportviewer and I don’t see a way forward. There’s an example I can rely on ?

  • @Diegofarias Calling the GC only makes the situation worse. Need to solve the problem that is causing this, which I do not know what is.

  • I get it, I’ll try other ways to solve.

Browser other questions tagged

You are not signed in. Login or sign up in order to post.