Empty Finalizer Body
ID |
java.no_empty_finalizer |
Severity |
high |
Remediation Complexity |
medium |
Remediation Risk |
low |
Remediation Effort |
medium |
Resource |
Efficiency |
Language |
Java |
Tags |
best-practice, efficiency |
Description
Reports a finalize() override whose body contains no statement. Comments are not statements, so a body holding only comments is reported as empty too.
An empty finalizer is not a harmless leftover. Declaring one makes the JVM register every instance of the type with the finalization queue, so those objects survive at least one extra collection cycle before their memory can be reclaimed — and nothing is released in return.
Rationale
class PageBuffer {
private final byte[] page = new byte[64];
@Override
protected void finalize() { // empty: costs a finalization round, releases nothing
}
}
Every PageBuffer now goes through the finalizer thread before it can be collected. The class pays the whole cost of finalization for a method that does nothing.
Two shapes are not reported:
-
A
finalempty finalizer. An emptyfinalfinalize()is the accepted defence against the finalizer attack — it stops a subclass from installing a finalizer that could resurrect a partially constructed object, and the body has to stay empty for the idiom to work. -
A method named
finalizethat takes parameters or returns a value. That is not the finalizer at all; a separate rule covers it.
Remediation
Delete the empty override. The type then follows the normal collection path with no finalization overhead:
class PageBuffer {
private final byte[] page = new byte[64];
}
If cleanup really is needed, do not put it in a finalizer: finalization runs at an unpredictable time, may never run at all, and swallows exceptions. Implement AutoCloseable and let callers use try-with-resources, or register the resource with a java.lang.ref.Cleaner.