I/O Advanced

Finalizers to deterministic resource cleanup

Replace finalization with AutoCloseable and use Cleaner only as a defensive fallback.

✕ 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.

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
Finalizers to deterministic resource cleanup
Available

Cleaner and finalization deprecation available since JDK 9 (September 2017)

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.