22

次の 2 つの質問に対する簡単な答えは見つかりませんでした。

  1. プロパティ インスタンスを削除する前にリスナーを削除する必要がありますか (リスナーは他の場所では使用されません)。

    BooleanProperty bool = new SimpleBooleanProperty();
    bool.addListener(myListener);
    bool.removeListener(myListener); // is it necessary to do this?
    bool = null;
    
  2. プロパティ インスタンスを削除する前に、一方向の境界付きプロパティをバインド解除する必要がありますか?

    BooleanProperty bool = new SimpleBooleanProperty();
    bool.bind(otherBool);
    bool.unbind(); // is it necessary to do this?
    bool = null;
    
4

2 に答える 2

31

ケース1

myListener「他の場所では使用されていない」ため、[method-] ローカル変数であると仮定すると、答えはnoです。ただし、一般的なケースでは、ほとんどの場合、答えはノーですが、イエスの場合もあります。

強力に到達可能である限りmyListener、ファイナライズの対象になることはなく、メモリを消費し続けます。myListenerたとえば、が「通常」宣言された変数である場合がこれに該当しstaticます (*Java のすべての「通常」参照は強い参照です*)。ただし、myListenerがローカル変数の場合、現在のメソッド呼び出しが返された後はオブジェクトに到達できなくなりbool.removeListener(myListener)、少し意味のないオーバーエンジニアリングになります。オブザーバーと の両方Observableが範囲外になり、最終的にファイナライズされます。この回答に関する私自身のブログ投稿からの引用は、より良い絵を描くかもしれません:

箱を海に投げれば、箱が中にいる猫を知っているかどうかは関係ありません。箱に手が届かない場合は、猫も手が届きません。

仮説

ここでの状況を完全に理解するには、Java オブジェクト ( source )のライフサイクルを思い出す必要があります。

参照オブジェクトをトラバースせずに何らかのスレッドが到達できる場合、そのオブジェクトは強力に到達可能です。新しく作成されたオブジェクトは、それを作成したスレッドから強力に到達可能です。[..] 強く [..] 到達可能 [..] ではないが、弱い参照をトラバースすることで到達できる場合、オブジェクトは弱く到達可能です。弱い到達可能オブジェクトへの弱い参照がクリアされると、オブジェクトはファイナライズの対象になります。

静的変数の場合、これらはクラスがロードされている限り常にアクセス可能であるため、到達可能です。静的参照がガベージ コレクターの仕事を妨げるものになりたくない場合は、WeakReference代わりに a を使用するように変数を宣言できます。JavaDoc は次のように述べています。

弱い参照オブジェクト [..] は、それらの参照先がファイナライズ可能になり、ファイナライズされてから再利用されることを妨げません。[..] ある時点でガベージ コレクタが、オブジェクトが到達しにくいと判断したとします。その時点で、そのオブジェクトへのすべての弱い参照をアトミックにクリアします [..]。同時に、以前は弱く到達可能だったすべてのオブジェクトがファイナライズ可能であると宣言します。

明示的な管理

説明のために、JavaFX スペース シミュレーション ゲームを作成するとします。惑星Observableが宇宙船の観測者の視界に入ると、ゲーム エンジンは宇宙船を惑星に登録します。惑星が見えなくなるたびに、ゲーム エンジンは を使用して、惑星のオブザーバーとしての宇宙船も削除する必要があることは明らかですObservable.removeListener()。そうしないと、宇宙船が宇宙を飛行し続けるときに、メモリ リークが発生します。最終的に、ゲームは観測された 50 億の惑星を処理できなくなり、OutOfMemoryError.

大部分の JavaFX リスナーとイベント ハンドラーのライフサイクルは、それらのライフサイクルと並行しているObservableため、アプリケーション開発者は何も心配する必要がないことに注意してください。たとえば、ユーザー入力を検証するリスナーをTextField作成し、テキスト フィールドのリスナーに登録する場合があります。textPropertyテキスト フィールドが存在している限り、リスナーも存在し続ける必要があります。遅かれ早かれ、テキスト フィールドは使用されなくなり、ガベージ コレクションが行われると、検証リスナーもガベージ コレクションの対象になります。

自動管理

宇宙シミュレーションの例を続けるために、ゲームのマルチプレイヤー サポートが制限されており、すべてのプレイヤーがお互いを観察する必要があると仮定します。おそらく、各プレイヤーはキル メトリックのローカル スコア ボードを保持するか、ブロードキャストされたチャット メッセージを観察する必要があるでしょう。理由はここでは重要なポイントではありません。プレイヤーがゲームをやめるとどうなりますか? 明らかに、リスナーが明示的に管理されていない (削除されている) 場合、終了したプレーヤーはファイナライズの対象になりません。他のプレーヤーは、オフライン プレーヤーへの強い参照を保持します。リスナーの明示的な削除は依然として有効なオプションであり、おそらく私たちのゲームにとって最も好ましい選択ですが、それが少し目障りに感じられ、より洗練された解決策を見つけたいとしましょう。

ゲーム エンジンは、すべてのプレイヤーがオンラインである限り、オンラインのすべてのプレイヤーへの強力な参照を保持することを知っています。そのため、ゲーム エンジンが強い参照を維持している間だけ、宇宙船が互いの変更やイベントをリッスンするようにしたいと考えています。「理論」セクションを読むと、確かにWeakReference解決策のように聞こえます。

ただし、何かを WeakReference でラップするだけでは、完全な解決策にはなりません。めったにありません。「指示対象」への最後の強い参照が に設定されているnullか、到達不能になっている場合、その指示対象はガベージ コレクションの対象になります (参照対象に a を使用して到達できないと仮定しますSoftReference)。しかし、WeakReference はまだぶらぶらしています。アプリケーション開発者は、配置されたデータ構造から WeakReference 自体が削除されるように、配管を追加する必要があります。そうでない場合は、メモリ リークの重大度を下げた可能性がありますが、動的に弱い追加が行われるため、メモリ リークは依然として存在します。参照もメモリを消費します。

幸運なことに、JavaFXは「自動削除」のメカニズムとしてインターフェースWeakListenerとクラスを追加しました。WeakEventHandler関連するすべてのクラスのコンストラクターは、クライアント コードによって提供される実際のリスナー/ハンドラーを受け入れますが、弱参照を使用してリスナー/ハンドラーを格納します。

の JavaDoc を見るとWeakEventHandler、クラスが を実装EventHandlerしていることがわかります。そのため、EventHandler が必要な場所ならどこでも WeakEventHandler を使用できます。同様に、 a の既知の実装は、WeakListeneranInvalidationListenerまたは aChangeListenerが期待される場所で使用できます。

のソース コードを調べるWeakEventHandlerと、このクラスは基本的に単なるラッパーであることがわかります。彼の指示対象 (実際のイベント ハンドラー) がガベージ コレクションされると、が呼び出されたWeakEventHandlerときに何もしないことで「動作を停止」します。WeakEventHandler.handle()は、自分がどのオブジェクトに接続されているかを認識していません。WeakEventHandlerたとえ接続していたとしても、イベント ハンドラーの削除は均一ではありません。ただし、すべての既知の実装クラスにWeakListenerは競争上の優位性があります。それらのコールバックが呼び出されると、Observableそれらが登録されている への参照が暗黙的または明示的に提供されます。そのため、 a の指示対象WeakListenerがガベージ コレクションされると、最終的に実装は、それ自体が からWeakListener確実に削除されるようにします。WeakListenerObservable

まだ明確でない場合、この宇宙シミュレーション ゲームの解決策は、ゲーム エンジンがすべてのオンライン宇宙船への強力な参照を使用できるようにすることです。宇宙船がオンラインになると、他のすべてのオンライン宇宙船は、 などの弱いリスナーを使用して新しいプレーヤーに登録されWeakInvalidationListenerます。プレーヤーがオフラインになると、ゲーム エンジンはプレーヤーへの強力な参照を削除し、プレーヤーはガベージ コレクションの対象になります。ゲーム エンジンは、オフライン プレーヤーを他のプレーヤーのリスナーとして明示的に削除する必要はありません。

ケース 2

いいえ。次に私が言うことをよりよく理解するために、最初にケース 1 の回答を読んでください。

BooleanPropertyBaseへの強力な参照を保存しotherBoolます。otherBoolこれ自体では、常に到達可能になるわけではないため、メモリ リークが発生する可能性があります。到達不能にboolなると、保存されているすべての参照も到達不能になります (他の場所に保存されていないと仮定します)。

BooleanPropertyBaseObserverバインド先のプロパティのとしてそれ自体を追加することによっても機能します。WeakListenerただし、ケース1の回答で説明したのとほぼ同じように機能するクラスにラップすることでそうします。したがって、 を無効boolにすると、 から削除されるのは時間の問題ですotherBool

于 2014-07-15T13:05:14.353 に答える