In one of my projects I was fighting with a memory leak the last couple of days (yes … “couple”) and I came to the conclusion that there might be an issue related to touch / scroll gestures. In the sample below I have two buttons. The first one creates a list view with one thousand rows, the second one removes it.
I made the following observations:
- when I click on “create” and immediately on “destroy” then everything will be garbage collected.
- when I click on “create” and use the scrollbar to scroll down and then click on “destroy” everything will be garbage collected.
- when I click on “create” and then use a gesture to scroll down (with my Mac Magic Mouse) then the garbage collection fails.
I have used jvisualvm that ships with the JDK and I use the “Sampler” tab to look at the heap space. I filter for the “TestItem” class and I can see that always those items are still in memory that were created for the last ListView after pressing the “create” button.
When I dump the heap and analyze it with the “Eclipse Memory Analyzer” I can see that it is most likely the ScrollGesture that keeps a reference to the list view / the data.
Can anyone confirm this? Is this a known bug? I could not find anything related to this issue in the Java bug database.
import java.util.ArrayList; import java.util.List; import javafx.application.Application; import javafx.scene.Scene; import javafx.scene.control.Button; import javafx.scene.control.ListView; import javafx.scene.layout.BorderPane; import javafx.scene.layout.HBox; import javafx.stage.Stage; public class MemoryLeakListViewApp extends Application { @Override public void start(Stage primaryStage) throws Exception { BorderPane pane = new BorderPane(); Scene scene = new Scene(pane); Button createButton = new Button("Create"); createButton.setOnAction(evt -> { ListView listView = new ListView(); List children = new ArrayList(); for (int i = 0; i < 1000; i++) { children.add(new TestItem("Row " + i)); } listView.getItems().setAll(children); pane.setCenter(listView); }); Button deleteButton = new Button("Destroy"); deleteButton.setOnAction(evt -> { pane.setCenter(null); }); HBox box = new HBox(); box.getChildren().addAll(createButton, deleteButton); pane.setTop(box); primaryStage.setScene(scene); primaryStage.setWidth(800); primaryStage.setHeight(800); primaryStage.show(); } static class TestItem { private String name; public TestItem(String name) { this.name = name; } @Override public String toString() { return name; } } public static void main(String[] args) { launch(args); } }
I’m facing the same issue in one of my projects and am currently advising our clients to disable multitouch entirely due to this issue. The only work around at the moment that I know of is to rebind your controls as much as possible instead of re-creating them from scratch, but that only limits the issue.
Thanks for describing the test case btw: maybe we can see a solution in one of the next JDK updates. 🙂
Do you know if there is a ticket for this in the Java bug database?
I tried searching for it again but couldn’t find anything either. Unless you can report bugs directly on the JDK JIRA, I would go through the channel at http://bugreport.java.com
[…] Lemmermann has three posts this week. Firstly, a post wondering if there is a TouchGesture memory leak in JavaFX. Secondly, a post beginning the JavaFX ‘Missing Features Survey’, starting […]
[…] Lemmermann has three posts this week. Firstly, a post wondering if there is a TouchGesture memory leak in JavaFX. Secondly, a post beginning the JavaFX ‘Missing Features Survey’, starting […]