9

Java でのファイナライズ可能なオブジェクトに関する議論では、通常、ファイナライズ可能なオブジェクト (およびそれらに関連するリソース) を迅速にガベージ コレクションできない場合に発生する一般的な間接コストについて説明します。

現時点では、ファイナライズ可能であることの実際の直接コストが、メモリとオブジェクトの割り当て時間の両方でどのくらいかということにもっと興味があります。このようなコストの存在について、さまざまな場所で斜めに言及しているのを見てきました。たとえば、ファイナライズ メモリ保持の問題に関する Oracle の記事では

obj割り当てられると、JVMobjはファイナライズ可能であることを内部的に記録します。これにより、通常、最新の JVM が持つ高速な割り当てパスが遅くなります。

JVM は、オブジェクト インスタンスがファイナライズ可能であることをどのように記録しますか? また、そのためにメモリとパフォーマンスのコストはどのくらいかかりますか?

私の特定のアプリケーションに興味がある人のために:

私たちは何百万もの信じられないほど軽量なオブジェクトを生成して保持しています。これらのオブジェクトに単一のポインターを追加するのは非常にコストがかかるため、フィールドのビットのサブセットにパックされた小さな数値 ID を使用する代わりに、オブジェクトからポインターを削除するためにかなりの作業を行いました。数値をアンパックすると、その ID を持つ共有の不変プロパティを、Map を使用してそれらを格納する Pool から取得できます。

残りの問題は、使用されなくなったプロパティ値のガベージ コレクションをどのように処理するかです。

検討されている戦略の 1 つは、参照カウントを使用することです。オブジェクトが作成され、プールされた値の ID を取得すると、その値の参照カウントがインクリメントされます。使用されなくなったら、デクリメントする必要があります。

このデクリメントを確実に行うためのオプションの 1 つは、次の finalize メソッドを追加することです。

public void finalize() {
    Pool.release(getPropertyId());
}

ただし、ファイナライズ可能であるという行為そのものが、オブジェクトへの追加のポインターを保持する必要があることを意味する場合、このアプリケーションでは、ファイナライズ可能であるための初期コストが高くなると見なされます。追加のオブジェクトを割り当てる必要があることを意味する場合、ほぼ確実に高すぎます...したがって、私の質問:ファイナライズ可能にするための直接の先行コストはいくらですか?

4

1 に答える 1

8

ファイナライザーは 、保持の問題だけでなく、パフォーマンスの観点からもひどいものです。

Oracle JDK/OpenJDK では、finalizeメソッドを持つオブジェクトは、 Finalizerのサブクラスであるjava.lang.ref.Reference.

すべてのファイナライザーは、オブジェクトのコンストラクターの最後で、Java から VM への呼び出しとそれに続くFinalizer.register()の呼び出しという 2 つの手順で登録されます。この二重遷移 Java->VM->Java は、JIT コンパイラーによってインライン化できません。しかし最悪の事態は、Finalizer のコンストラクターがグローバル ロックの下にリンク リストを作成することです。(フェイスパーム)

ファイナライザは、メモリ フットプリントの点でも良くありません。すべての参照フィールドに加えて、ファイナライザには2 つの追加フィールドnextがありprevます:

PhantomReferences は、ファイナライザーよりもはるかに優れています。

  • それらの構築は、VM への移行とその逆を必要とせず、インライン化できます。
  • から継承する以外に追加のフィールドはありませんjava.lang.ref.Reference
  • グローバル同期は行われません。

このベンチマークでは、ファイナライズ可能なオブジェクトと PhantomReference によってサポートされるオブジェクトの割り当て速度を比較します。

Benchmark               Mode  Cnt       Score      Error   Units
Finalizer.finalizable  thrpt    5    2171,312 ± 1469,705  ops/ms
Finalizer.phantom      thrpt    5   61280,612 ±  692,922  ops/ms
Finalizer.plain        thrpt    5  225752,307 ± 7618,304  ops/ms
于 2015-05-08T21:12:43.320 に答える