JavaFX - 垃圾收集无法清理 objects

JavaFX - Garbage collection fails to clean up objects

我一直在努力弄清楚如何处理我正在处理的 JavaFX 应用程序中的内存泄漏。我使用以下代码使用 FX8 来测试内存行为:

import javafx.application.Application;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.input.KeyEvent;
import javafx.scene.input.KeyCode;
import javafx.scene.paint.Color;
import javafx.scene.shape.Rectangle;
import javafx.stage.Stage;

public class Main extends Application {

    public int count = 0;

    @Override
    public void start(Stage stage) {
        Group root = new Group();
        Scene scene = new Scene(root, 500, 500, Color.BLACK);

        Rectangle r = new Rectangle(25,25,250,250);
        r.setFill(Color.BLUE);
        root.getChildren().add(r);

        scene.addEventHandler(KeyEvent.KEY_RELEASED, event -> {
            if (event.getCode() == KeyCode.SPACE) {
                event.consume();
                count++;
                Rectangle r2 = new Rectangle(25, 25, 250, 250); 
                r2.setFill(Color.BLUE);
                root.getChildren().clear();
                root.getChildren().add(r2);
            }
        });

        stage.setTitle("JavaFX Scene Graph Demo");
        stage.setScene(scene);
        stage.show();
    }

    public static void main(String[] args) {
        launch(args);
    }
}

每当按下 SPACE 时,root 的 children 就会被清除,并在 root 上附加一个新的矩形.

此代码的问题在于,随着 SPACE 被反复按下,Java 应用程序使用的内存量不断增加。即使应用程序在一段时间后处于空闲状态,应用程序使用的内存量也不会减少。

我的印象是 Rectangle objects 应该被垃圾回收了,但内存量并没有减少。这是 JavaFX 的问题,还是关于 Java 垃圾收集的一些我不知道的事情?


编辑: 使用 System.gc() 和 YourKit

在@AlmasB 的回答之后,我添加了一个 System.gc() 回调调用,这样每当按下 SPACE 时,建议执行 GC垃圾回收。

YourKit 显示垃圾收集确实在进行,事实上,如 YourKit 所示,使用的堆和 Non-Heap 内存量在 SPACE被重复按下。

TLDR:即使 GC 正在执行它的工作并且 YourKit 报告内存稳定,应用程序的内存消耗也会继续逐渐增加,如 Activity 监视器所报告的那样。这是 Activity 监视器的问题吗?

Java 中的垃圾收集并不意味着在每个对象在没有强引用的情况下超出范围后进行清理。当您的 Rectangle 对象不再可访问时,即当您清除根子项时,该对象将被简单地标记为垃圾回收但仍保留在内存中。您可以阅读更多 here and more general info here。所以从技术上讲,根据您的 JVM 环境,GC 甚至可能不会 运行 在您的应用程序的生命周期内,因为有足够的内存来分配新对象。

如果您仍然认为存在内存泄漏,我建议您在担心 JavaFX 或 GC 可能存在错误之前使用适当的分析工具,例如 VisualVM 和 VisualGC。