Od finalizatorów do deterministycznego zwalniania zasobów
Zastąp finalizację interfejsem AutoCloseable, a Cleaner stosuj tylko jako awaryjne zabezpieczenie.
@Override
protected void finalize() throws Throwable {
nativeHandle.release();
}
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();
}
}
Deterministyczność
Try-with-resources zwalnia zasoby w znanym momencie.
Bezpieczniejszy cykl życia
Eliminuje wskrzeszanie obiektów przez finalizator i nieprzewidywalną kolejność.
Awaryjne zabezpieczenie
Cleaner może odzyskać zasoby po wycieku bez przesłaniania finalize().
Cleaner i oznaczenie finalizacji jako przestarzałej są dostępne od JDK 9 (wrzesień 2017)
Finalizacja jest przestarzała i przeznaczona do usunięcia; nie zapewnia ani szybkiego zwalniania zasobów, ani niezawodnej kolejności. Zaimplementuj AutoCloseable, aby kod wywołujący mógł deterministycznie zwalniać zasoby za pomocą try-with-resources. W przypadku wycieku zasobów Cleaner może w ostateczności wywołać tę samą idempotentną operację czyszczenia; jego akcja nie może przechowywać referencji do zarejestrowanego obiektu.