JavaFX - 垃圾收集无法清除对象

时间:2015-07-01 09:17:32

标签: java memory-leaks javafx garbage-collection

我一直在努力弄清楚如何处理我正在处理的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的孩子都会被清除,并且root会附加一个新的矩形。

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

我的印象是Rectangle对象应该被垃圾收集,但内存量不会减少。这是JavaFX的问题,还是我不知道的Java垃圾收集问题?

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

按照@ AlmasB的回答,我在回调中添加了System.gc()调用,这样每当按下 SPACE 时,建议GC执行垃圾回收。 / p>

YourKit显示垃圾收集确实正在进行,事实上,堆的数量和如YouKit所示,使用的非堆内存会在一段时间后稳定,即使重复按下 SPACE

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

1 个答案:

答案 0 :(得分:3)

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

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