Is it normal in javafx to keep on increasing memory usage as columns in tableview is sorted?

I would like to know if the following two observations are normal in JavaFX:

  • I notice the memory usage of my JavaFX app increasing drastically(90mb) every time a column in the table view is sorted. (My data is an ObservableList. Tableview will have 71000 rows and 13 columns)
  • Sorting of a column with double datatype takes too long and way too much memory (about 250mb).

Note: I am using java 10.0.2

My TableView code:

private TableView table = new TableView();

table.setEditable(true);
    TableColumn<TableViewWatchlistData, Boolean> colSelected = new TableColumn<>("Selected");
    colSelected.setCellFactory(tc ->{return new CheckBoxTableCell();});
    colSelected.setEditable(true);
    colSelected.setCellValueFactory(new PropertyValueFactory<>("isEntered"));


    TableColumn<TableViewWatchlistData, String> colInstToken = new TableColumn<>("Instrument Token");
    colInstToken.setCellValueFactory(new PropertyValueFactory<>("instrumentToken"));

    TableColumn<TableViewWatchlistData, String> colExngToken = new TableColumn<>("Exchange Token");
    colExngToken.setCellValueFactory(new PropertyValueFactory<>("exchangeToken"));

    TableColumn<TableViewWatchlistData, String> colTradSymbol = new TableColumn<>("Symbol");
    colTradSymbol.setCellValueFactory(new PropertyValueFactory<>("tradingSymbol"));

    TableColumn<TableViewWatchlistData, String> colExngName = new TableColumn<>("Exchange");
    colExngName.setCellValueFactory(new PropertyValueFactory<>("exchangeName"));

    TableColumn<TableViewWatchlistData, String> colCompName = new TableColumn<>("Company Name");
    colCompName.setCellValueFactory(new PropertyValueFactory<>("companyName"));

    TableColumn<TableViewWatchlistData, Double> colLastPrice = new TableColumn<>("Last Price");
    colLastPrice.setCellValueFactory(new PropertyValueFactory<>("lastPrice"));

    TableColumn<TableViewWatchlistData, LocalDate> colExpiry = new TableColumn<>("Expiry Date");
    colExpiry.setCellValueFactory(new PropertyValueFactory<>("expiry"));

    TableColumn<TableViewWatchlistData, Double> colStrike = new TableColumn<>("Strike");
    colStrike.setCellValueFactory(new PropertyValueFactory<>("strike"));

    TableColumn<TableViewWatchlistData, Double> colTick = new TableColumn<>("Tick");
    colTick.setCellValueFactory(new PropertyValueFactory<>("tickSize"));

    TableColumn<TableViewWatchlistData, Integer> colLotSize = new TableColumn<>("Lot Size");
    colLotSize.setCellValueFactory(new PropertyValueFactory<>("lotSize"));

    TableColumn<TableViewWatchlistData, String> colInstType = new TableColumn<>("Instrument Type");
    colInstType.setCellValueFactory(new PropertyValueFactory<>("instrumentType"));

    TableColumn<TableViewWatchlistData, String> colSegment = new TableColumn<>("Segment");
    colSegment.setCellValueFactory(new PropertyValueFactory<>("segment"));

    TableColumn<TableViewWatchlistData, LocalDateTime> colLastUpdated = new TableColumn<>("Last Updated");
    colLastUpdated.setCellValueFactory(new PropertyValueFactory<>("lastUpdated"));

    colSelected.setMinWidth(70);
    colInstToken.setMinWidth(120);
    colExngToken.setMinWidth(110);
    colTradSymbol.setMinWidth(110);
    colExngName.setMinWidth(75);
    colCompName.setMinWidth(210);
    colLastPrice.setMinWidth(75);
    colExpiry.setMinWidth(85);
    colStrike.setMinWidth(55);
    colTick.setMinWidth(45);
    colLotSize.setMinWidth(65);
    colInstType.setMinWidth(110);
    colSegment.setMinWidth(75);
    colLastUpdated.setMinWidth(135);

    table.getColumns().setAll(colSelected,colInstToken,colExngToken,colTradSymbol,colExngName,colCompName,colLastPrice,colExpiry,colStrike,colTick,colLotSize,colInstType,colSegment,colLastUpdated);

    colSelected.setSortType(TableColumn.SortType.DESCENDING);
    table.getSortOrder().setAll(colSelected);
    colSelected.setSortable(true);

    this.kdk.generateTableViewData(watchlistname);

    ObservableList<TableViewWatchlistData> items = FXCollections.observableArrayList(this.kdk.watchlistTableViewData.values());
    SortedList<TableViewWatchlistData> data = new SortedList<>(items);
    data.comparatorProperty().bind(table.comparatorProperty());

    table.setItems(data);
    table.sort();
}

TableView Data Model:

import javafx.beans.property.*;
import kite2ami.Instruments;

public class TableViewWatchlistData {

private final SimpleStringProperty instrumentToken = new SimpleStringProperty();
private final SimpleStringProperty exchangeToken = new SimpleStringProperty();
private final SimpleStringProperty tradingSymbol = new SimpleStringProperty();
private final SimpleStringProperty companyName = new SimpleStringProperty();
private final SimpleDoubleProperty lastPrice = new SimpleDoubleProperty();
private final SimpleObjectProperty<LocalDate> expiry = new SimpleObjectProperty<LocalDate>();
private final SimpleDoubleProperty strike = new SimpleDoubleProperty();
private final SimpleDoubleProperty tickSize = new SimpleDoubleProperty();
private final SimpleIntegerProperty lotSize = new SimpleIntegerProperty();
private final SimpleStringProperty instrumentType = new SimpleStringProperty(); //PE, CE, EQ, FUT
private final SimpleStringProperty segment = new SimpleStringProperty();
private final SimpleStringProperty exchangeName = new SimpleStringProperty();
private final SimpleBooleanProperty isEntered = new SimpleBooleanProperty();
private final SimpleObjectProperty<LocalDateTime> lastUpdated = new SimpleObjectProperty<>();

public TableViewWatchlistData(Instruments instrument, boolean isEntered) {
    this.setInstrumentToken(instrument.getInstrumentToken());
    this.setExchangeToken(instrument.getExchangeToken());
    this.setTradingSymbol(instrument.getTradingSymbol());
    this.setCompanyName(instrument.getCompanyName());
    this.setLastPrice(instrument.getLastPrice());
    this.setExpiry(instrument.getExpiry());
    this.setStrike(instrument.getStrike());
    this.setTickSize(instrument.getTickSize());
    this.setLotSize(instrument.getLotSize());
    this.setInstrumentType(instrument.getInstrumentType());
    this.setSegment(instrument.getSegment());
    this.setExchangeName(instrument.getExchangeName());
    this.setIsEntered(isEntered);
    this.setLastUpdated(instrument.getLastUpdated());
}

public String getInstrumentToken() {
    return instrumentToken.get();
}

public SimpleStringProperty instrumentTokenProperty() {
    return instrumentToken;
}

public void setInstrumentToken(String instrumentToken) {
    this.instrumentToken.set(instrumentToken);
}

public String getExchangeToken() {
    return exchangeToken.get();
}

public SimpleStringProperty exchangeTokenProperty() {
    return exchangeToken;
}

public void setExchangeToken(String exchangeToken) {
    this.exchangeToken.set(exchangeToken);
}

public String getTradingSymbol() {
    return tradingSymbol.get();
}

public SimpleStringProperty tradingSymbolProperty() {
    return tradingSymbol;
}

public void setTradingSymbol(String tradingSymbol) {
    this.tradingSymbol.set(tradingSymbol);
}

public String getCompanyName() {
    return companyName.get();
}

public SimpleStringProperty companyNameProperty() {
    return companyName;
}

public void setCompanyName(String companyName) {
    this.companyName.set(companyName);
}

public double getLastPrice() {
    return lastPrice.get();
}

public SimpleDoubleProperty lastPriceProperty() {
    return lastPrice;
}

public void setLastPrice(double lastPrice) {
    this.lastPrice.set(lastPrice);
}

public LocalDate getExpiry() {
    return expiry.get();
}

public SimpleObjectProperty<LocalDate> expiryProperty() {
    return expiry;
}

public void setExpiry(LocalDate expiry) {
    this.expiry.set(expiry);
}

public double getStrike() {
    return strike.get();
}

public SimpleDoubleProperty strikeProperty() {
    return strike;
}

public void setStrike(double strike) {
    this.strike.set(strike);
}

public double getTickSize() {
    return tickSize.get();
}

public SimpleDoubleProperty tickSizeProperty() {
    return tickSize;
}

public void setTickSize(double tickSize) {
    this.tickSize.set(tickSize);
}

public int getLotSize() {
    return lotSize.get();
}

public SimpleIntegerProperty lotSizeProperty() {
    return lotSize;
}

public void setLotSize(int lotSize) {
    this.lotSize.set(lotSize);
}

public String getInstrumentType() {
    return instrumentType.get();
}

public SimpleStringProperty instrumentTypeProperty() {
    return instrumentType;
}

public void setInstrumentType(String instrumentType) {
    this.instrumentType.set(instrumentType);
}

public String getSegment() {
    return segment.get();
}

public SimpleStringProperty segmentProperty() {
    return segment;
}

public void setSegment(String segment) {
    this.segment.set(segment);
}

public String getExchangeName() {
    return exchangeName.get();
}

public SimpleStringProperty exchangeNameProperty() {
    return exchangeName;
}

public void setExchangeName(String exchangeName) {
    this.exchangeName.set(exchangeName);
}

public boolean isIsEntered() {
    return isEntered.get();
}

public SimpleBooleanProperty isEnteredProperty() {
    return isEntered;
}

public void setIsEntered(boolean isEntered) {
    this.isEntered.set(isEntered);
}

public LocalDateTime getLastUpdated() {
    return lastUpdated.get();
}

public SimpleObjectProperty<LocalDateTime> lastUpdatedProperty() {
    return lastUpdated;
}

public void setLastUpdated(LocalDateTime lastUpdated) {
    this.lastUpdated.set(lastUpdated);
}
}

1 answer

  • answered 2019-04-21 10:48 aiyu

    I managed to resolve the issue by changing the following:

    colSelected.setCellValueFactory(cellData->cellData.getValue().isEnteredProperty());
    

    to

    colSelected.setCellValueFactory(new PropertyValueFactory<>("isEntered"));
    

    I still don't understand what changed under the hood. But it resolves my issue. If anybody could enlighten me it would be kind of you.