1

JavaFX アプリを設計しています。ユーザーイベント(ボタンのクリックなど)に応じてユーザー入力を動的に(FXMLから)収集するために使用されるダイアログフォーム/ウィンドウをロードし、ユーザーが操作を終了したときにウィンドウを「アンロード」することにしました。形成し、それを却下します。

各 FXML フォームがロードされた後、ダイアログがユーザーに表示される前に初期化する必要があるリストビュー、テーブルビュー、およびコンボボックスがあります。この目的で使用するコードの一部を次に示します。

@FXML // This method is called by the FXMLLoader when 
      //initialization is complete

void initialize() {

    // Initialize your logic here: all @FXML variables will have been injected

    ObservableList<Institution> ilist = Institution.getInstitutionList();
    Callback<ListView<Institution>, ListCell<Institution>> cellfactory =
            new Callback<ListView<Institution>, ListCell<Institution>>() {
                @Override
                public ListCell<Institution> call(ListView<Institution> p) {
                    return new InstitutionListCell();
                }
            };

    cbxInst.setCellFactory(cellfactory);
    cbxInst.setButtonCell(cellfactory.call(null));
    cbxInst.setPromptText(CensusAssistant.RES_STRING_INSTSELECT);
    cbxInst.setItems(ilist);
    cbxInst.setDisable((ilist.size() < 1));


    Callback<ListView<Rotation>, ListCell<Rotation>> rotfactory =
            new Callback<ListView<Rotation>, ListCell<Rotation>>() {
                @Override
                public ListCell<Rotation> call(ListView<Rotation> p) {
                    return new EncRotationListCell();
                }
            };
    :
    :

すべてのコードを表示したくありません。ここでのポイントは、Cell のサブクラス (ListCell など) を使用するフォーム上のすべてのコントロールに対して、セル ファクトリを提供するために匿名の内部クラスを使用していることです。

これらの匿名内部クラスは、それらを囲むクラスへの参照を保持します。私の結論は、これらの参照により、ユーザーがフォームを閉じた後の任意の時点でフォームがガベージ コレクションされるのを防ぐことができるということです。そのため、セッション中にフォームを何度も開いたり閉じたりすると、メモリ リークの問題が発生するのではないかと心配しています。

私はこれについて目標を達成していますか?ユーザーがフォームを閉じたときにセル ファクトリをコントロールから切り離すコードを記述する必要がありますか? これは一般的に、イベントリスナー (または内部クラスを使用して一般的に対処されるもの) の問題ですか? オブジェクトが解放される前に、常にイベントまたはアクション ハンドラーの登録を解除するのが賢明ですか?

編集:

これらと同じ問題の多くは、この投稿で処理されています: (匿名の) 内部クラスを使用しても安全なのはいつですか? .

ウィンドウが繰り返し構築されて閉じられる可能性があるこの状況では、JavaFX コントローラー クラスへの潜在的に長命の参照をすべて無効にする必要があると考える傾向があると思います。特に細胞工場。

4

1 に答える 1

1

Java ガベージ コレクションの簡単な紹介。これはおそらくあなたが持っているものに似ているオブジェクトツリーです:

Window
   |-- AnchorPane
            |-- ListView
            |-- Label

正確に再現しようとしているわけではなく、単なる例です。ここで、Window から AnchorPane を削除すると、AnchorPane、ListView、および Label が最終的に収集され、メモリ リークにはなりません。AnchorPane への参照を別のオブジェクトに渡す場合は、オブジェクトを再利用するために両方の参照を削除する必要があります。

メモリ リークを引き起こさないコード開発方法を試して設計し、避けられないミスをテストする方が簡単だと思います。


それについて考える最良の方法は、オブジェクトが存続する期間です。ウィンドウのコンテンツが別のフォームに切り替えられている場合、ウィンドウはコンテンツよりも長く存続します。ドメイン オブジェクトとサービスの一部は、コンテンツよりも長く存続する場合もあります。オブジェクトの相対寿命を計算したら、次の規則に従うことができます。

存続期間の短いオブジェクトが存続期間の長いオブジェクトを参照することは問題ありませんが、その逆は問題ありません。

この例では、ListView が Window (長寿命オブジェクト) または Label (等寿命オブジェクト) への参照を持っていても、メモリ リークは発生しません。Window はより短い AnchorPane を参照するため、Window の子から手動で削除する必要があります。長い参照から短い参照については、手動で削除する必要があります。これはバグの可能性があるため、これを行う必要がある場合もありますが、これらの関係を最小限に抑えることをお勧めします。

コードを所有していないバインディングとシーン グラフの場合は、何が変更される可能性があるかを参照する実装であるため、これらの参照を常に手動で削除する必要があると想定することをお勧めします。

于 2013-05-03T23:11:54.757 に答える