2 Replies Latest reply: Feb 21, 2013 3:32 PM by qwerty1 RSS

    Table cell update on demand causes memory leaks

    qwerty1
      I use listeners to update my table cells instead of binding everything to observable properties (reason is that I can't afford to create a property for every of a 1000 rows and 20 columns, yeah, big data set!)

      Problem is that FX created hundreds of PersonTableCell which are never disposed of by garbage collector because (my guess is that) every PersonTableCell holds a reference to oldPerson !!!
      So after a while my app has 10000 PersonTableCell which are not reusable and can't be disposed of by GC which renders this approach useless but approach seems valid !... I think I am doing something wrong here

      Does anyone have any ideas??? Any help is greatly appreciated !

      Here is my cell renderer..

      private class PersonTableCell extends TableCell<Person, Person> {
      private Person oldPerson;
      private InvalidationListener listener;

      protected void updateItem(final Person person, boolean empty) {
      super.updateItem(mediaNode, empty);

      if(oldPerson != null) {
      oldPerson.removeListener(listener);
      oldPerson = null;
      }

      if(!empty) {
      listener = new InvalidatonListener() {
      public void invalidated(Observable o) {
      setText(person.getTitle());
      }
      };
      oldPerson = person;
      person.addListener(listener);
      setText(person.getTitle());
      }
      }
      }
      This approach is described at Re: TableView auto update issue in 2.1 and 2.2
      and again, seems rather witty one to avoid huge number of SimpleProperty objects. If only I could make it work :)

      Please help !
        • 1. Re: Table cell update on demand causes memory leaks
          dxryan
          I don't have a direct answer for memory leaks within a tableview, but I would like to suggest a few things:

          1. I have found it easier (in my rewarding 7 months experience with JavaFX) to use the TableColumn API than TableCell for populating a table. The TableColumn API for JavaFX 2.2 has a nice example, plus there are probably plenty of examples in the JavaFX website and this forum. I typically use the .setCellValueFactory and .setCellFactory methods. If nothing else it changes your problem from dealing with 10000 rows to 20 columns. Would this reduce your memory load?

          2. You might also look at the Cell API. There is a section titled Cell Factories which seems to contradict the idea that there would be 10000 cells created at once. I pasted part of that section below:

          The cell factory is called by the platform whenever it determines that a new cell needs to be created. For example, perhaps your ListView has 10 million items. Creating all 10 million cells would be prohibitively expensive. So instead the ListView skin implementation might only create just enough cells to fit the visual space. If the ListView is resized to be larger, the system will determine that it needs to create some additional cells. In this case it will call the cellFactory callback function (if one is provided) to create the Cell implementation that should be used. If no cell factory is provided, the built-in default implementation will be used.

          The API references ListView, but it seems reasonable to assume it applies to TableView as well.

          I did find a posting on this forum which seemed to indicate that Oracle was aware of the memory leak issue and hoped to address it in version 2.2. I am not sure if that happened.
          • 2. Re: Table cell update on demand causes memory leaks
            qwerty1
            Thank you for looking !

            Of course I use setCellValueFactory and setCellFactory methods. I added a code snippet below.
            However problem is that there are way too many PersonTableCell created. Yes, they are not created at once but they are created every time I add a row and that is what my table handles. So if you need to reflect a change of data every couple of seconds and waiting for an hour to update a table is not an option one have to add a new row every few seconds. Hence 20 new PersonTableCell (since there are 2 0 columns) are created for every row and never deleted. That's my problem ! That they are not deleted and I don't understand why. Unfortunately I haven't found a solution anywhere in this forum or anywhere else on the net. Not that I didn't look ! :)

            Thanks again for looking !

            TableColumn column = new TableColumn(name);
            column.setCellValueFactory(new Callback....
            {
                 ...
            });
            column.setCellFactory(new MyCellFactory());



            class MyCellFactory implements Callback<TableColumn, TableCell>
            {
            public TableCell call(TableColumn p)
            {
            return new PersonTableCell();
            }
            }

            //as posted above already

            class PersonTableCell extends TableCell<Person, Person> {     
                 private Person oldPerson;
                 private InvalidationListener listener;
                 ....
            }