The term finalizer is mostly used in object-oriented and functional programming languages that use garbage collection, of which the archetype is Smalltalk.
This is contrasted with a destructor, which is a method called for finalization in languages with deterministic object lifetimes, archetypically C++.
[2][3] These are generally exclusive: a language will have either finalizers (if automatically garbage collected) or destructors (if manually memory managed), but in rare cases a language may have both, as in C++/CLI and D, and in case of reference counting (instead of tracing garbage collection), terminology varies.
In common use, a destructor is a method called deterministically on object destruction, and the archetype is C++ destructors; while a finalizer is called non-deterministically by the garbage collector, and the archetype is Java finalize methods.
For languages that implement garbage collection via reference counting, terminology varies, with some languages such as Objective-C and Perl using destructor, and other languages such as Python using finalizer (per spec, Python is garbage collected, but the reference CPython implementation since its version 2.0 uses a combination of reference counting and garbage collection).
In certain narrow technical use, constructor and destructor are language-level terms, meaning methods defined in a class, while initializer and finalizer are implementation-level terms, meaning methods called during object creation or destruction.
[4][5] This terminology is confusing, and thus more recent versions of the C# spec refer to the language-level method as "finalizers".
[6] Another language that does not make this terminology distinction is D. Although D classes are garbage collected, their cleanup functions are called destructors.
This latter can cause problems due to the garbage collector being unable to track these external resources, so they will not be collected aggressively enough, and can cause out-of-memory errors due to exhausting unmanaged memory – this can be avoided by treating native memory as a resource and using the dispose pattern, as discussed below.
They are much less necessary because garbage collection automates memory management, and much less used because they are not generally executed deterministically – they may not be called in a timely manner, or even at all, and the execution environment cannot be predicted – and thus any cleanup that must be done in a deterministic way must instead be done by some other method, most frequently manually via the dispose pattern.
Due to the lack of programmer control over their execution, it is usually recommended to avoid finalizers for any but the most trivial operations.
This is particularly common among C++ programmers, as destructors are heavily used in idiomatic C++, following the resource acquisition is initialization (RAII) idiom.
In this case resources may still be acquired in the initializer, which is called explicitly on object instantiation, but are released in the dispose method.
The dispose method may be called explicitly, or implicitly by language constructs such as C#'s using, Java's try-with-resources, or Python's with.
However, in languages with non-deterministic object lifetimes – which include all major languages with garbage collection, such as C#, Java, and Python – this does not work, because finalization may not be timely or may not happen at all, and thus resources may not be released for a long time or even at all, causing resource leaks.
In some cases both techniques are combined, using an explicit dispose method, but also releasing any still-held resources during finalization as a backup.
Apple versions[clarification needed]) for similar reasons, treating resurrection as a bug.
A different approach is used in the .NET Framework, notably C# and Visual Basic .NET, where finalization is tracked by a "queue", rather than by object.
These are particularly used when using finalization for resource management as a supplement to the dispose pattern, or when implementing an object pool.
This asymmetry means that finalization cannot be effectively used as the complement of initialization, because it does not happen in a timely manner, in a specified order, or in a specified environment.
[a][15] The introduction of Java in 1995 contained finalize methods, which popularized the term and associated it with garbage collection, and languages from this point generally make this distinction and use the term "finalization", particularly in the context of garbage collection.