首页 > 解决方案 > RAM 过度支出 - JavaFX

问题描述

在每次场景变化时,内存的使用都会增加并且永远不会“清理”,如果我来回通过2个屏幕,同样的情况会发生几次,每次进入同一个屏幕都会增加使用,只有第一个屏幕对于第二个我们可以看到使用减少的地方,是在图形中用红色标记的地方。

在此处输入图像描述

请注意,垃圾收集只会增加:

在此处输入图像描述

要更改场景,我使用以下代码:

public void changeStage(Parent event, String title, String url){
    Platform.runLater(() -> {
        try {
            Parent loader = FXMLLoader.load(getClass().getResource("/gro/admin/java/" + url));
            event.getScene().setRoot(loader);

        } catch (IOException ex) {
            Logger.getLogger(LoginController.class.getName()).log(Level.SEVERE, null, ex);

        } 
    });
}

经过搜索,我看到这System.gc();可能会有所帮助,但没有效果。我试图让所有对象都变为 null 并调用它以尝试释放 RAM 但没有效果:

Call changeStage(this, stackPane, "Title", "Url");This在这种情况下是实现 Initializable 的类本身

public void changeStage(Object obj, Parent event, String title, String url){
    Platform.runLater(() -> {
        try {
            nullAll(obj, event);
            Parent loader = FXMLLoader.load(getClass().getResource("/gro/admin/java/" + url));
            event.getScene().setRoot(loader);

        } catch (IOException ex) {
            Logger.getLogger(LoginController.class.getName()).log(Level.SEVERE, null, ex);

        } 
    });
}

private static void nullAll(Object obj, Parent root){
    ObservableList<Node> nodes = getAllViews(root);
    nodes.forEach(node -> node = null);
    nodes.clear();
    nodes = null;
    if(root instanceof StackPane){
        ((StackPane) root).getChildren().clear();
        root = null;

    }else{
        root = null;

    }

    obj = null;
    System.gc();
}

private static ObservableList<Node> getAllViews(Parent root) {
    ObservableList<Node> nodes = FXCollections.observableArrayList();
    addAllDescendents(root, nodes);
    return nodes;
}

private static void addAllDescendents(Parent parent, ObservableList<Node> nodes) {
    parent.getChildrenUnmodifiable().stream().map((node) -> {
        nodes.add(node);
        return node;
    }).map((node) -> {
        if (node instanceof Parent){
            addAllDescendents((Parent) node, nodes);

        }
        return node;            
    }).map((node) -> {
        if(node instanceof ScrollPane){
            addAllDescendents((Parent) ((ScrollPane) node).getContent(), nodes);
            nodes.add(((ScrollPane) node).getContent());
        }
        return node;            
    }).map((node) -> {
        if(node instanceof TabPane){
            ((TabPane) node).getTabs().forEach((t) -> {
                addAllDescendents((Parent) ((Tab) t).getContent(), nodes);
            });
        }
        return node;
    }).filter((node) -> (node instanceof JFXTabPane)).forEachOrdered((node) -> {
        ((JFXTabPane) node).getTabs().forEach((t) -> {
            addAllDescendents((Parent) ((Tab) t).getContent(), nodes);
        });
    });
}

这并没有影响记忆中​​的任何东西,只是让场景的交换“哽咽”了一些。

有谁知道我如何才能在没有这种不必要的“堆积”的情况下改变场景?

编辑:啊,另一个有趣的点,在使用过程中内存的使用从 1gb 很容易,但如果我使用一些 ram 清理程序,它会低于 100mb。

前:

在此处输入图像描述

后:

在此处输入图像描述

标签: javaperformancejavafxjavafx-8

解决方案


历史悠久:这与您的代码无关,而与 Java 的工作方式有关。JavaFX 通常需要更多内存,它会根据需要消耗更多内存,因为默认情况下,即使您触发垃圾收集,Java 也不会将内存返回给您的系统,因此如果 JavaFX 程序需要大量内存来处理但释放之后,JRE 将永远保持最大内存水平,垃圾收集器将不那么频繁地被触发,因为有很多空闲的未使用内存,但是,您可以更改 JVM 行为,如何分配内存,它是如何分配的释放并触发 GC 时,请参阅性能调优指南


推荐阅读