jav*_*jon 4 java memory-leaks javafx javafx-2 javafx-8
在下面的示例中,如果继续按"下一组"按钮,最终应用程序堆将耗尽.将堆设置为较小的数字,例如-mx50m -ms50m,它将很快达到上限.您可以看到JVisualVM之类的经典楼梯内存消耗.在使用YourKit进行性能分析时,发现有许多来自javafx.*和java.*类包的对象实例没有被CG.setPageFactory似乎是罪魁祸首.也许这段代码做的事情不应该,但到目前为止,我怀疑Windows 8上的JavaFX 2.2分页控制,JDK 1.7_60.Window 8,Java FX 8,JDK 1.8_05也出现了同样的问题.
这是示例或JavaFX Pagination.setPageFactory的问题吗?
public class PaginationSample extends Application {
private static final String[] PAGE_TEXTS_0 = {"Time wounds all heals.", "The more I see, the less I know for sure.",
"Reality leaves a lot to the imagination.", "It's weird not to be weird."};
private static final String[] PAGE_TEXTS_1 = {"Fermions", "Quarks", "Leptons", "Bosons", "Gluon", "Graviton"};
private static final String[] PAGE_TEXTS_2 = {"AAAAAAA", "BBBBB", "CCCCCCCC"};
private static final String[][] ALL_GROUPS = {PAGE_TEXTS_0, PAGE_TEXTS_1, PAGE_TEXTS_2};
private int groupIndex;
@Override
public void start(Stage stage) {
final Pagination pagination = new Pagination();
setPagesGroup(pagination);
Button button = new Button("Next group");
button.setOnAction(new EventHandler<ActionEvent>() {
@Override
public void handle(ActionEvent actionEvent) {
nextGroup();
setPagesGroup(pagination);
}
});
BorderPane pane = new BorderPane();
pane.setCenter(pagination);
pane.setBottom(button);
stage.setScene(new Scene(pane, 400, 250));
stage.setTitle("What's leaking?");
stage.show();
}
private void setPagesGroup(Pagination pagination) {
pagination.setPageFactory(createPageFactory());
pagination.setPageCount(ALL_GROUPS[groupIndex].length);
}
private Callback<Integer, Node> createPageFactory() {
return new Callback<Integer, Node>() {
@Override
public Node call(Integer pageIndex) {
return createPage(ALL_GROUPS[groupIndex][pageIndex]);
}
private Node createPage(String text) {
return new Label(text);
}
};
}
private void nextGroup() {
if (++groupIndex == ALL_GROUPS.length) {
groupIndex = 0;
}
}
public static void main(String... args) {
launch(args);
}
}
Run Code Online (Sandbox Code Playgroud)
下面测试期间剖析器的证据.在测试之前和结束时,强制进行垃圾收集.

补充调查:
如果行
// pagination.setPageFactory(createPageFactory());
Run Code Online (Sandbox Code Playgroud)
注释掉该示例仍然有效,因为工厂仍在提供页面,而setPageCount方法强制PaginationSkin类调用其resetIndexes方法.setPageFactory和setPageCount都调用PaginationSkin.resetIndexes并发生内存消耗.也许PaginationSkin.java有问题?
请投票支持待解决的问题,您必须登录.
https://javafx-jira.kenai.com/browse/RT-38058
Java 7和8代码调用
pagination.setPageFactory(...);
pagination.setPageCount(...);
Run Code Online (Sandbox Code Playgroud)
会引发这种泄漏.
PaginationSkin类似乎有泄漏.验证从中复制源
然后通过消除和分析内存的过程,你会发现内部类IndicatorButton中的这两个添加侦听器导致泄漏:
@ line 1179
getSkinnable().getStyleClass().addListener(new ListChangeListener<String>() {
@Override
public void onChanged(Change<? extends String> change) {
setIndicatorType();
}
});
@ line 1197
tooltipVisibleProperty().addListener(new ChangeListener<Boolean>() {
@Override
public void changed(ObservableValue<? extends Boolean> ov, Boolean oldValue, Boolean newValue) {
setTooltipVisible(newValue);
}
});
Run Code Online (Sandbox Code Playgroud)
由于内部类后引用,在从节点树中删除IndicatorButton对象后,垃圾收集器无法删除这些对象事件(getChildren.clear()).在IDE中,如果暂时使IndicatorButton静态,则可以中断编译并查看对外部类的突出显示的引用.当这两个听众被注释掉时,泄漏就会消失.如果您将这两个侦听器保留在其中,并在侦听器中注释掉工作代码行,则仍会发生泄漏.
解: