To get a trial key
fill out the form below
Team License (a basic version)
Enterprise License (an extended version)
* By clicking this button you agree to our Privacy Policy statement

Request our prices
New License
License Renewal
--Select currency--
* By clicking this button you agree to our Privacy Policy statement

Free PVS-Studio license for Microsoft MVP specialists
* By clicking this button you agree to our Privacy Policy statement

To get the licence for your open-source project, please fill out this form
* By clicking this button you agree to our Privacy Policy statement

I am interested to try it on the platforms:
* By clicking this button you agree to our Privacy Policy statement

Message submitted.

Your message has been sent. We will email you at

If you haven't received our response, please do the following:
check your Spam/Junk folder and click the "Not Spam" button for our message.
This way, you won't miss messages from our team in the future.

Why using finalizers is a bad idea

Why using finalizers is a bad idea

Oct 07 2016

Not so long ago we worked on a diagnostic rule related to the finalizer check. This provoked an argument on the details of the garbage collector work and the finalization of objects. Although we have been programming in C# for more than 5 years, we haven't achieved any consensus as regards this question, so I decided to study it more thoroughly.



Usually .NET developers encounter a finalizer when they need to free an unmanaged resource. That's when a programmer has to think about a specific question: should we implement in our class IDisposable, or add a finalizer? Then he goes to StackOverflow, for example, and reads answers to questions like the Finalize/Dispose pattern in C#, where he sees a classic pattern of IDisposable implementation, and the definition of the finalizer. The same pattern can be found in the MSDN description of the IDisposable interface. Some consider it quite complicated to understand, and offer other options like implementing the clearing of managed and unmanaged resources in separate methods, or creating a wrapper class especially for freeing unmanaged resource. You can find them on the same page on StackOverflow.

Most of these methods suggest implementing a finalizer. Let's see what the benefits are, and what potential problems it can bring.

The pros and cons of using finalizers


  • A finalizer allows the clearing an object before it will be deleted by a garbage collector. If the developer forgot to call Dispose() method of an object, then it will be possible to free the unmanaged resources and thus, avoid the leak.

Well, that's it. That is the only plus, and it is quite controversial; we'll speak about the details later.


  • The finalization is not determined. You don't know when the finalizer will be called. Before CLR starts finalizing the objects, the garbage collector should place it in the queue of objects, ready for the finalization, when the next garbage collection starts. But this point is not defined.
  • Due to the fact that an object with the finalizer does not get removed by the garbage collector immediately, the object, and the entire graph of dependent objects, go through the garbage collection and promote to the next generation. They will be removed only when the garbage collector decides to collect objects of this generation, which can take quite a while.
  • Since the finalizers run in a separate thread in parallel with other threads of the application, a programmer may have a situation when the new objects, requiring finalization, will be created faster than the finalizers of old objects will complete the execution. This will lead to increased memory consumption, decreased performance, and perhaps eventually to the crash of the application with OutOfMemoryException. On the developer's machine you may never encounter this situation, for example because you have fewer processors, or the objects are created slower or the application does not work as long as it could and the memory doesn't run out as fast. It may take a lot of time to realize that the reason was the finalizers. Perhaps this minus outweighs the benefits of the only pro.
  • If there is an exception during the finalizer execution, then the application will terminate. Therefore, if you implement a finalizer, you should be especially careful: do not access the methods of other objects for which the finalizer could be called; take into account that a finalizer is called in a separate thread; verify against null all other objects that could potentially be null. The last rule is related to the fact that the finalizer can be called for an object in any of its states, even incompletely initialized. For example, if you always assign in the constructor a new object in the class field and then expect that in the finalizer it should never be null and do access it, then you can get NullReferenceException, if there was an exception in the base class constructor during the creation of an object, and your constructor wasn't executed at all.
  • A finalizer may be not executed at all. Upon the abortion of the application, for example, if there is an exception thrown in somebody's finalizer due to any of the reasons described above, no other finalizers will be executed. If you free unmanaged objects of the operating system, there will be nothing wrong in the way that the operating system returns its resources when the application terminates. But if you put unwritten bytes to the file, you will lose your data. So, perhaps it would be better not to implement the finalizer, but let the data be lost, in case you forgot to call Dispose(), because in this case the problem will be easier to find.
  • We should remember that the finalizer is called only once, and if you resurrect the object in the finalizer by means of assigning a reference to it to a different live object, then perhaps, you should register it for the finalization again with the help of the method GC.ReRegisterForFinalize().
  • You can face the problems of multithread applications; for example, the race condition, even if your application is single-threaded. This would be a very unusual case, but it is theoretically possible. Suppose there is a finalizer in your object, it is referenced by a different object that also has a finalizer. If both objects become eligible for garbage collection, and their finalizers start executing at the same time another object gets resurrected, then that object and your object become alive again. Now we may have a situation where the method of your object will be called from the main thread and from the finalizer at the same time, because it is still in the queue of objects, ready for the finalization. The code that reproduces this example is given below: You can see that first the finalizer of the Root object is executed, then the finalizer of the Nested object, and then the method DoSomeWork() is called from two threads at the same time.
class Root
    public volatile static Root StaticRoot = null;
    public Nested Nested = null;

        Console.WriteLine("Finalization of Root");
        StaticRoot = this;
class Nested
    public void DoSomeWork()
            "Thread {0} enters DoSomeWork",
            "Thread {0} leaves DoSomeWork",
        Console.WriteLine("Finalization of Nested");

class Program
    static void CreateObjects()
        Nested nested = new Nested();
        Root root = new Root();
        root.Nested = nested;
    static void Main(string[] args)
        while (Root.StaticRoot == null) { }

This is what will be be displayed on my machine:

Finalization of Root
Finalization of Nested
Thread 10 enters DoSomeWork
Thread 2 enters DoSomeWork
Thread 10 leaves DoSomeWork
Thread 2 leaves DoSomeWork

If your finalizers called in a different order, try to change the places of the creation of nested and root.


Finalizers in .NET are the easiest way to shoot yourself in the foot. Before you rush into adding finalizers for all the classes that are implementing IDisposable, think first; do you really need them that much? It should be noted that the CLR developers warn against their use on the page the Dispose Pattern: "Avoid making types finalizable. Carefully consider any case in which you think a finalizer is needed. There is a real cost associated with instances with finalizers, from both a performance and code complexity standpoint."

But if you decide to use finalizers anyway, PVS-Studio will help you find potential bugs. We have the V3100 diagnostic, which can indicate all spots in the finalizer where there is a possibility of NullReferenceException.

Popular related articles
Technologies used in the PVS-Studio code analyzer for finding bugs and potential vulnerabilities

Date: Nov 21 2018

Author: Andrey Karpov

A brief description of technologies used in the PVS-Studio tool, which let us effectively detect a large number of error patterns and potential vulnerabilities. The article describes the implementati…
How PVS-Studio Proved to Be More Attentive Than Three and a Half Programmers

Date: Oct 22 2018

Author: Andrey Karpov

Just like other static analyzers, PVS-Studio often produces false positives. What you are about to read is a short story where I'll tell you how PVS-Studio proved, just one more time, to be more atte…
Free PVS-Studio for those who develops open source projects

Date: Dec 22 2018

Author: Andrey Karpov

On the New 2019 year's eve, a PVS-Studio team decided to make a nice gift for all contributors of open-source projects hosted on GitHub, GitLab or Bitbucket. They are given free usage of PVS-Studio s…
The Ultimate Question of Programming, Refactoring, and Everything

Date: Apr 14 2016

Author: Andrey Karpov

Yes, you've guessed correctly - the answer is "42". In this article you will find 42 recommendations about coding in C++ that can help a programmer avoid a lot of errors, save time and effort. The au…
The way static analyzers fight against false positives, and why they do it

Date: Mar 20 2017

Author: Andrey Karpov

In my previous article I wrote that I don't like the approach of evaluating the efficiency of static analyzers with the help of synthetic tests. In that article, I give the example of a code fragment…
Appreciate Static Code Analysis!

Date: Oct 16 2017

Author: Andrey Karpov

I am really astonished by the capabilities of static code analysis even though I am one of the developers of PVS-Studio analyzer myself. The tool surprised me the other day as it turned out to be sma…
PVS-Studio for Java

Date: Jan 17 2019

Author: Andrey Karpov

In the seventh version of the PVS-Studio static analyzer, we added support of the Java language. It's time for a brief story of how we've started making support of the Java language, how far we've co…
Static analysis as part of the development process in Unreal Engine

Date: Jun 27 2017

Author: Andrey Karpov

Unreal Engine continues to develop as new code is added and previously written code is changed. What is the inevitable consequence of ongoing development in a project? The emergence of new bugs in th…
The Evil within the Comparison Functions

Date: May 19 2017

Author: Andrey Karpov

Perhaps, readers remember my article titled "Last line effect". It describes a pattern I've once noticed: in most cases programmers make an error in the last line of similar text blocks. Now I want t…
The Last Line Effect

Date: May 31 2014

Author: Andrey Karpov

I have studied many errors caused by the use of the Copy-Paste method, and can assure you that programmers most often tend to make mistakes in the last fragment of a homogeneous code block. I have ne…

Comments (0)

Next comments
This website uses cookies and other technology to provide you a more personalized experience. By continuing the view of our web-pages you accept the terms of using these files. If you don't want your personal data to be processed, please, leave this site.
Learn More →