Skip to content

Commit

Permalink
8237926: Potential memory leak of model data in javafx.scene.control.…
Browse files Browse the repository at this point in the history
…ListView

Reviewed-by: kcr, aghaisas
  • Loading branch information
arapte committed Mar 5, 2020
1 parent 960f039 commit 337ed72
Show file tree
Hide file tree
Showing 4 changed files with 12 additions and 39 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@
import javafx.collections.ListChangeListener;
import javafx.collections.ObservableList;
import javafx.collections.ObservableListBase;
import javafx.collections.WeakListChangeListener;

import java.lang.ref.WeakReference;
import java.util.ArrayList;
Expand All @@ -38,20 +37,7 @@ public abstract class SelectedItemsReadOnlyObservableList<E> extends ObservableL

// This is the actual observable list of selected indices used in the selection model
private final ObservableList<Integer> selectedIndices;

private ObservableList<E> itemsList;

private boolean itemsListChanged = false;
private ListChangeListener.Change<? extends E> itemsListChange;
private final ListChangeListener itemsListListener = c -> {
itemsListChanged = true;
itemsListChange = c;
};
private final WeakListChangeListener weakItemsListListener =
new WeakListChangeListener(itemsListListener);

private final Supplier<Integer> modelSizeSupplier;

private final List<WeakReference<E>> itemsRefList;

public SelectedItemsReadOnlyObservableList(ObservableList<Integer> selectedIndices, Supplier<Integer> modelSizeSupplier) {
Expand Down Expand Up @@ -100,9 +86,6 @@ public SelectedItemsReadOnlyObservableList(ObservableList<Integer> selectedIndic
itemsRefList.add(new WeakReference<>(getModelItem(selectedIndex)));
}

itemsListChanged = false;
itemsListChange = null;

endChange();
});
}
Expand All @@ -120,17 +103,6 @@ public int size() {
return selectedIndices.size();
}

// Used by ListView and TableView to allow for improved handling.
public void setItemsList(ObservableList<E> itemsList) {
if (this.itemsList != null) {
this.itemsList.removeListener(weakItemsListListener);
}
this.itemsList = itemsList;
if (itemsList != null) {
itemsList.addListener(weakItemsListListener);
}
}

private E _getModelItem(int index) {
if (index >= modelSizeSupplier.get()) {
// attempt to return from the itemsRefList instead
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,6 @@
import java.util.List;

import com.sun.javafx.scene.control.Properties;
import com.sun.javafx.scene.control.SelectedItemsReadOnlyObservableList;
import com.sun.javafx.scene.control.behavior.ListCellBehavior;
import javafx.beans.InvalidationListener;
import javafx.beans.Observable;
Expand Down Expand Up @@ -1221,9 +1220,6 @@ public ListViewBitSetSelectionModel(final ListView<T> listView) {

this.listView = listView;

((SelectedItemsReadOnlyObservableList)getSelectedItems()).setItemsList(listView.getItems());


/*
* The following two listeners are used in conjunction with
* SelectionModel.select(T obj) to allow for a developer to select
Expand All @@ -1238,7 +1234,6 @@ public ListViewBitSetSelectionModel(final ListView<T> listView) {
@Override public void invalidated(Observable observable) {
ObservableList<T> oldItems = weakItemsRef.get();
weakItemsRef = new WeakReference<>(listView.getItems());
((SelectedItemsReadOnlyObservableList)getSelectedItems()).setItemsList(listView.getItems());
updateItemsObserver(oldItems, listView.getItems());
}
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,6 @@
import com.sun.javafx.scene.control.Logging;
import com.sun.javafx.scene.control.Properties;
import com.sun.javafx.scene.control.SelectedCellsMap;
import com.sun.javafx.scene.control.SelectedItemsReadOnlyObservableList;
import com.sun.javafx.scene.control.behavior.TableCellBehavior;
import com.sun.javafx.scene.control.behavior.TableCellBehaviorBase;

Expand Down Expand Up @@ -2104,8 +2103,6 @@ public TableViewArrayListSelectionModel(final TableView<S> tableView) {
ObservableList<S> oldItems = weakItemsRef.get();
weakItemsRef = new WeakReference<>(tableView.getItems());
updateItemsObserver(oldItems, tableView.getItems());

((SelectedItemsReadOnlyObservableList)getSelectedItems()).setItemsList(tableView.getItems());
}
};
this.tableView.itemsProperty().addListener(itemsPropertyListener);
Expand Down Expand Up @@ -2142,7 +2139,6 @@ public TableViewArrayListSelectionModel(final TableView<S> tableView) {
// watching for changes to the items list content
ObservableList<S> items = getTableView().getItems();
if (items != null) {
((SelectedItemsReadOnlyObservableList)getSelectedItems()).setItemsList(items);
items.addListener(weakItemsContentListener);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1982,10 +1982,20 @@ public void testListViewLeak() {
ObservableList<String> items = FXCollections.observableArrayList();
WeakReference<ListView<String>> listViewRef = new WeakReference<>(new ListView<>(items));
attemptGC(listViewRef, 10);
assertNull("ListView has a leak.", listViewRef.get());
assertNull("ListView is not GCed.", listViewRef.get());
}

private void attemptGC(WeakReference<ListView<String>> weakRef, int n) {
@Test
public void testItemLeak() {
WeakReference<String> itemRef = new WeakReference<>(new String("Leak Item"));
ObservableList<String> items = FXCollections.observableArrayList(itemRef.get());
ListView<String> listView = new ListView<>(items);
items.clear();
attemptGC(itemRef, 10);
assertNull("ListView item is not GCed.", itemRef.get());
}

private void attemptGC(WeakReference<? extends Object> weakRef, int n) {
for (int i = 0; i < n; i++) {
System.gc();
System.runFinalization();
Expand Down

0 comments on commit 337ed72

Please sign in to comment.