Finalizer with an empty body, or one that only calls MyBase.Finalize
ID |
vbnet.performance.no_empty_finalizer |
Severity |
low |
Remediation Complexity |
trivial |
Remediation Risk |
low |
Remediation Effort |
low |
Resource |
Performance |
Language |
VB.NET |
Description
Reports a Protected Overrides Sub Finalize whose body is empty or whose only statement is the
base call MyBase.Finalize(). Such a finalizer performs no cleanup, yet declaring it changes
how the garbage collector treats every instance of the type.
Rationale
Declaring Finalize makes the type finalizable, so the runtime adds each new instance to the
finalization queue. That instance can no longer be reclaimed in the generation where it died:
the collector must first promote it, run the finalizer on the dedicated finalizer thread, and
only reclaim the memory on a later collection. The type pays that cost - an extra allocation
record, a promotion, and at least one extra collection per object - to run a method that does
nothing. In a hot allocation path this turns cheap gen-0 garbage into surviving objects and
measurably increases both pause times and peak memory. A body consisting only of
MyBase.Finalize() is equivalent: Object.Finalize is empty, and the compiler emits that call
at the end of every finalizer anyway.
The following code illustrates the pattern detected by this rule:
Private _handle As IntPtr
' FLAGGED: Finalizer with an empty body, or one that only calls MyBase.Finalize
Protected Overrides Sub Finalize()
End Sub
Remediation
Delete the finalizer. Keep one only when the type directly owns an unmanaged resource - a raw
handle or unmanaged memory - and then have it release that resource; prefer wrapping the handle
in SafeHandle and implementing IDisposable, which removes the need for a finalizer
altogether.
' Before: makes every instance finalizable and cleans up nothing
Protected Overrides Sub Finalize()
MyBase.Finalize()
End Sub
' After: no finalizer; the handle owns its own cleanup
Private ReadOnly _handle As SafeFileHandle
Public Sub Dispose() Implements IDisposable.Dispose
_handle.Dispose()
End Sub
References
-
https://learn.microsoft.com/en-us/dotnet/fundamentals/code-analysis/quality-rules/ca1821
-
https://learn.microsoft.com/en-us/dotnet/api/system.object.finalize
-
https://learn.microsoft.com/en-us/dotnet/standard/garbage-collection/implementing-dispose
-
https://learn.microsoft.com/en-us/dotnet/api/microsoft.win32.safehandles.safehandle