2017-07-12 28 views
1

私は巨大なJavaFXアプリケーションを持っています。これは主にFXMLファイルを使用してビューを作成していますが、メモリ使用量が高いことに気付きましたが、しばらくそれを無視しています。調査の後、フォームのガベージコレクタを閉じた後でジョブと使用済みメモリが解放されるため、すべての単一ビューが多く消費されていることがわかりました。 たとえば、スクロールすると、テーブルビューをスローします。 780メガバイト,,JavaFX - メモリ消費

Table View Table View Memory Consumption

から1000の要素[スクリーンショットを添付]、350メガバイトのメモリ使用スパイクがまったく同じではテーブルビューの同じデータを示すリストビューをスロースクロールで発生します:

List View List View Memory Consumption

質問は,,その正常ですか?または私は多分、私が列を生成するために、次のやっているテーブルビューの場合

UPDATE

何か間違ったことをやって:

public static <T> TableColumn<T, T> generateGraphicColumn(String title, Callback<TableColumn<T, T>, TableCell<T, T>> callback) { 
    TableColumn<T, T> column = generateColumn(title, null); 
    column.setCellValueFactory(new Callback<TableColumn.CellDataFeatures<T, T>, ObservableValue<T>>() { 

     @Override 
     public ObservableValue<T> call(CellDataFeatures<T, T> param) { 
      SimpleObjectProperty<T> s = new SimpleObjectProperty<>(); 
      s.setValue(param.getValue()); 
      return s; 
     } 
    }); 
    column.setCellFactory(callback); 
    return column; 
} 

public static <T> TableColumn<T, T> generateGraphicColumn(String title, Callback<TableColumn<T, T>, TableCell<T, T>> callback, double width) { 

    TableColumn<T, T> column = generateGraphicColumn(title, callback); 
    column.setMaxWidth(width); 
    column.setMinWidth(width); 
    return column; 

} 
public static <T,S> TableColumn<T, S> generateColumn(String title, 
     Callback<TableColumn.CellDataFeatures<T, S>, ObservableValue<S>> propertyValueFactory) { 

    TableColumn<T, S> column; 
    column = new TableColumn<>(); 
    if (propertyValueFactory != null) 
     column.setCellValueFactory(propertyValueFactory); 
    column.setStyle(column.getStyle() + "-fx-alignment: BASELINE_CENTER;"); 
    column.setText(title); 
    return column; 

} 

をし、私は次のように上記のコードを使用しています:

{ // status 
     TableColumn<Visit, Visit> column = TableViewUtilities.generateGraphicColumn(text("General.STATUS"), 
       new Callback<TableColumn<Visit, Visit>, TableCell<Visit, Visit>>() { 
        @Override 
        public TableCell<Visit, Visit> call(final TableColumn<Visit, Visit> param) { 
         final TableCell<Visit, Visit> cell = new TableCell<Visit, Visit>() { 

          @Override 
          public void updateItem(Visit item, boolean empty) { 

           super.updateItem(item, empty); 


           if (empty || getIndex() < 0) { 
            setGraphic(null); 
            setText(null); 
            return; 
           } 

           item = getTableView().getItems().get(getIndex()); 

           Label label = new Label(); 
           StackPane pane = new StackPane(label); 
           pane.setAlignment(Pos.CENTER); 
           label.setMaxWidth(10); 
           label.setMinWidth(10); 
           label.setMinHeight(30); 

           setText(item.getStatus().display()); 
           String background = FXMLConstants .toHexString(ColorUtils.getVisitBackgroundColor(item)); 
           pane.setStyle(String.format("-fx-background-color:%s;;", background)); 
           setGraphic(pane); 
           setText(item.getStatus().display()); 
           setStyle(getStyle() + "-fx-alignment: CENTER_LEFT;"); 
          } 
         }; 
         return cell; 
        } 
       }, 100); 

     column.setComparator(VisitCommonHelper.getCompByStatus()); 
     tblVisits.getColumns().add(column); 
    } 
+0

これは、テーブルの行のデータ型と表示方法(カスタムセルファクトリ)によって大きく異なります。コンテキストがなくても正常である(つまり、データモデルとして使用されるクラスおよびテーブル上で使用される任意のセルファクトリ)ことは言うまでもありません。 – Itai

+0

@sillyfly親切に更新をチェックして、テーブルの列をどのように作成しているのかの例を追加しました –

答えて

3

空でないセルの更新ごとに新しいLabelStackPaneを作成しています。ヒープの使用率が上昇する理由を説明しますが、ガベージコレクションされる可能性があります。

あなたは(あなたのケースではStackPaneLabel)あなたのノードをキャッシュすることによってそれを解決しようとすることができます - 一度だけ、それを作成:

final TableCell<Visit, Visit> cell = new TableCell<Visit, Visit>() { 
    private Label label; 
    private StackPane pane; 
    { 
     // This is the constructor of the anonymous class. Alternatively, you may choose to create the label and pane lazily the first time they're needed. 
     label = new Label(); 
     pane = new StackPane(label); 
     pane.setAlignment(Pos.CENTER); 
     label.setMaxWidth(10); 
     label.setMinWidth(10); 
     label.setMinHeight(30); 
    } 

    @Override 
    public void updateItem(Visit item, boolean empty) { 
     super.updateItem(item, empty); 
     if (empty || getIndex() < 0) { 
      setGraphic(null); 
      setText(null); 
      return; 
     } 
     item = getTableView().getItems().get(getIndex()); 

     setText(item.getStatus().display()); 

     String background = FXMLConstants.toHexString(ColorUtils.getVisitBackgroundColor(item)); 
     pane.setStyle(String.format("-fx-background-color:%s;;", background)); 
     setGraphic(pane); 
     setText(item.getStatus().display()); 
     setStyle(getStyle() + "-fx-alignment: CENTER_LEFT;"); 
    } 
}; 

をも - ラベルの使用は何ですか、あなたはそのを設定しない場合テキスト?セルのcontentDisplayとは何ですか?ノードは表示されていますか?

+0

解決策が実際に問題を解決しました、ラベルが使用されていました。 ,,, 1つの質問thou、なぜ私はifステートメントを持っている場合は、スタックペインを作成する場合は、セルが空の場合に返されますか?ありがとうございました –

+0

別の質問、もし同じアプリケーションのスイングバージョンが150 MBのRAMを使用していれば、私たちはUIのみを改造しました。今は350 MBかかります。悪いデザインの選択やFXグラフィックスが重いだけです –

+1

スイングとJavaFXは全く別のツールキットなので、メモリ使用量を直接比較することはできません。あなたが作ることができる他の最適化が常にあるかもしれませんが、あなたは本当に2つを比較することはできません。なぜ新しいペインが作成されたのか - 空のセルの場合は新しいペインは作成されませんが、JavaFXの 'TableView'(' ListView'、 'TreeTableView'など)は"仮想ノード " - 異なるアイテムに対して同じ 'Cell'を効果的に再利用するので、' updateItem'メソッドは、スクロール時に複数回呼び出されます。これは、各セルに表示されるアイテムが変更されるためです。 – Itai