Abdullah Asendar
Abdullah Asendar

Reputation: 604

JavaFX - Memory Consumption

I have a huge JavaFX application that mostly uses FXML files to create the views, i noticed high memory usage but have been ignoring it for a while. After investigation i found that every single view is consuming a lot, however, after closing the form garbage collector does the job and used memory is released. For example, scrolling throw a table view that has approx. 1000 elements [screen shot attached], the memory usage spikes from 350 MB to 780 MB,,

Table View Table View Memory Consumption

The exact same happens on scrolling throw a list view that shows the same data of the table view :

List View List View Memory Consumption

the question is,, is that normal? or i maybe doing something wrong

UPDATE

For table view i am doing the following to generate a column:

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;

}

and i am using code above as following:

    { // 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);
    }

Upvotes: 1

Views: 2645

Answers (1)

Itai
Itai

Reputation: 6911

You are creating a new Label and StackPane for every non-empty cell update, which may explain why the heap usage rises but may be garbage-collected.

You can try solving it by caching your node (Label in a StackPane in your case) - creating it only once:

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;");
    }
};

Also - what is the use of the label, if you never set its text? What is the contentDisplay of the cell? Are the nodes even shown?

Upvotes: 3

Related Questions