0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

Effective Java(第3版) 項目8 ファイナライザとクリーナーを避ける

Posted at

ファイナライザ、クリーナは一般には不要なため、使用することを避けるべき、という内容です。

記載内容

クリーナー、ファイナライザ共通

クリーナー、ファイナライザが実行されるまでの時間は予想できない

実行までの時間的な制約がある処理をクリーナー、ファイナライザで行うべきではない。

例えばファイルのクローズをクリーナー、ファイナライザに頼るべきではない。
クリーナー、ファイナライザの実行が遅れると、オープン可能なファイル数の限界に達し、
新しいファイルのオープンでエラーになる可能性がある。

クリーナー、ファイナライザを実装するよりも、
AutoCloseableを実装し、使用側でtry-with-resourcesを使うべきである。

クリーナーの正当な使い方は二つある。

  • クローズを呼び忘れた場合の保険
  • ネイティブピアの回収

クリーナー、ファイナライザの実行は言語仕様上は保証されていない

DBのロック開放の様な、永続的な状態の更新をクリーナー、ファイナライザで行うべきではない。

パフォーマンスの劣化

クリーナー、ファイナライザを使用した場合、GCに関して深刻なパフォーマンスの劣化が発生する。
著者の環境では
クリーナー、ファイナライザ呼び出しと伴うGC処理は50倍程度、
クリーナを保険として使用している場合でも5倍程度遅くなる。

ファイナライザ

ファイナライザはJava9より非推奨になっており、使用するべきではない。
ファイナライザはセキュリティ問題を抱えており、悪意のあるサブクラスでファイナライザを実装することで、
不正なオブジェクト参照を取得することが可能になる。
これを防ぐには、クラスをfinalにするか、何もしないfinalのファイナライザを書けば良い。

クリーナー

クリーナーはファイナライザよりは良いが、動作は予想不可能で遅く、また、一般的には使用する必要はない。
クリーナーのAPIは少々扱いづらいが、クラスのpublicのAPIに影響しない。
例として、AutoCloseableを実装したクラスに対して、
クローズ漏れに対する保険としてクリーナーを使用するのは、問題はない。
ただし、クリーナーが確実に実行されるとは限らない。
System.exitや、通常のプログラム終了に対するクリーナーの動作は実装に依存し、
実行は保証されない。

考察

かなり以前から、ファイナライザは使うべきではない、というのが一般的だったと思いますが、
非推奨になっており、明確に使うべきではない、という状態になっています。

ただし、代替となるクリーナーも、セキュリティ以外のファイナライザの欠点である

  • 実行タイミングが分からない
  • 確実に実行されるとは限らない

はそのままですので、やはり確実な後処理には向かないです。

try-with-resourcesを使い、ファイルのオープンのように、使用上限がある重要な資源であれば、
保険でクリーナーを使用する、程度の使い方にとどまるかと思います。
ただし、GCに関するパフォーマンスの問題がありますので、AutoCloseableなクラス全てで
クリーナーを使う、というのは避けるべきかと思います。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?