TableView memory leak

XMLWordPrintable

    • Type: Bug
    • Resolution: Fixed
    • Priority: P4
    • 8
    • Affects Version/s: 7u15
    • Component/s: javafx
    • None

      TableCell's add a listener to the visibleLeafColumns property of TableView in the method TableCell.tableViewPropertyImpl(). This listener is not removed until the TableCells tableView property changes (which is probably almost never). We have long running fast moving tables and this leak is catastrophic for our application.

      We have hacked via reflection into the guts of TableView to clean up these references ourselves. It ain't pretty but it works. Should help you identify exactly where the issue is:

      static {
                  vlcField = TableView.class.getDeclaredField("visibleLeafColumns");
                  vlcField.setAccessible(true);

                  listenerHelperField = ObservableListWrapper.class.getDeclaredField("listenerHelper");
                  listenerHelperField.setAccessible(true);

                  weakRefField = WeakListChangeListener.class.getDeclaredField("ref");
                  weakRefField.setAccessible(true);

      }

         public static void reap(TableView<?> tableView) {
              try {
                  List<ListChangeListener> toRemove = null;
                  ObservableListWrapper<?> visibleLeafColumns = (ObservableListWrapper<?>) vlcField.get(tableView);
                  ListListenerHelper<?> listenerHelper = (ListListenerHelper<?>) listenerHelperField.get(visibleLeafColumns);
                  if (listenerHelper != null) {
                      Field changeListenersField = listenerHelper.getClass().getDeclaredField("changeListeners");
                      changeListenersField.setAccessible(true);
                      ListChangeListener<?>[] changeListeners = (ListChangeListener<?>[]) changeListenersField.get(listenerHelper);
                      for (ListChangeListener<?> changeListener : changeListeners) {
                          if (changeListener instanceof WeakListChangeListener) {
                              WeakReference weakReference = (WeakReference) weakRefField.get(changeListener);
                              if (weakReference != null && weakReference.get() == null) {
                                  if (toRemove == null) {
                                      toRemove = new ArrayList<ListChangeListener>();
                                  }
                                  toRemove.add(changeListener);
                              }
                          }
                      }
                  }
                  if (toRemove != null) {
                      System.out.println("Removing " + toRemove.size() + " refs");
                      for (ListChangeListener listChangeListener : toRemove) {
                          visibleLeafColumns.removeListener(listChangeListener);
                      }
                  }
              } catch (Exception ignore) {
              }
          }

            Assignee:
            Jonathan Giles
            Reporter:
            Craig Day (Inactive)
            Votes:
            0 Vote for this issue
            Watchers:
            2 Start watching this issue

              Created:
              Updated:
              Resolved:
              Imported: