ファイナライザーから決定的なリソースクリーンアップへ
ファイナライゼーションをAutoCloseableに置き換え、Cleanerは防御的なフォールバックとしてのみ使用する。
コード比較
✕ 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();
}
}
このコードに問題がありますか? お知らせください。
モダンな方法が優れている理由
決定的
Try-with-resourcesは既知の時点でリソースを解放します。
より安全なライフサイクル
ファイナライザーによるオブジェクトの復活と予測不能な実行順序を回避できます。
防御的なフォールバック
Cleanerはfinalize()をオーバーライドせずに、解放されずに残ったリソースを回収できます。
旧来のアプローチ
finalize()のオーバーライド
モダンなアプローチ
AutoCloseableとCleaner
JDKバージョン
9
難易度
上級
JDKサポート
ファイナライザーから決定的なリソースクリーンアップへ
利用可能
Cleanerとファイナライゼーションの非推奨化はJDK 9(2017年9月)以降、利用可能
仕組み
ファイナライゼーションは削除予定として非推奨であり、迅速なクリーンアップも信頼できる実行順序も保証しません。AutoCloseableを実装すると、呼び出し側はtry-with-resourcesを使用して決定的にリソースを解放できます。解放されずに残ったリソースについては、最後の手段としてCleanerから同じ冪等なクリーンアップ処理を呼び出せます。その処理が登録対象のオブジェクトを保持してはなりません。
関連ドキュメント
証明