Finalizers to deterministic resource cleanup
Replace finalization with AutoCloseable and use Cleaner only as a defensive fallback.
Code Comparison
✕ Finalization
@Override
protected void finalize() throws Throwable {
nativeHandle.release();
}
✓ Java 9+
final class NativeResource implements AutoCloseable {
private static final Cleaner CLEANER = Cleaner.create();
private static final class State implements Runnable {
private final long handle;
State(long handle) {
this.handle = handle;
}
@Override
public void run() {
release(handle);
}
}
private final Cleaner.Cleanable cleanable;
NativeResource(long handle) {
cleanable = CLEANER.register(this, new State(handle));
}
@Override
public void close() {
cleanable.clean();
}
}
See a problem with this code? Let us know.
Why the modern way wins
Deterministic
Try-with-resources releases resources at a known point.
Safer lifecycle
Avoids finalizer resurrection and unpredictable ordering.
Defensive fallback
Cleaner can recover leaked resources without overriding finalize().
Old Approach
Override finalize()
Modern Approach
AutoCloseable and Cleaner
Since JDK
9
Difficulty
Advanced
JDK Support
Finalizers to deterministic resource cleanup
Available
Cleaner and finalization deprecation available since JDK 9 (September 2017)
How it works
Finalization is deprecated for removal and provides neither prompt cleanup nor reliable ordering. Implement AutoCloseable so callers can release resources deterministically with try-with-resources. For leaked resources, Cleaner can invoke the same idempotent cleanup action as a last resort; its action must not retain the registered object.
Related Documentation
Proof