JavaFX无限期时间轴中的内存泄漏 [英] Memory leak in JavaFX indefinite Timeline

查看:179
本文介绍了JavaFX无限期时间轴中的内存泄漏的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用JavaFX设计秒表。代码运行良好。除了巨大的累积内存泄漏随着时间的推移。每当我增加时间轴帧速率时,泄漏就会增加。我目前使用的是4GB内存的Ubuntu 16.04,泄漏速度为300MB / min,速度为30fps。那是5MBps。我可以理解,由于重复绘制场景,可能会发生这种情况,但为什么会累积? JVM不应该解决这个问题吗?

I'm designing a stopwatch using JavaFX. The code runs well. Except for enormous cumulative memory leaks over time. The leak increases whenever I increase the Timeline's framerate. I'm currently on Ubuntu 16.04 with 4gigs of RAM, and the leak is happening at a speed of 300MB/min at 30fps. That's 5MBps. I can understand that this may happen due to the repetitive drawing over the Scene, but why would it be cumulative? Shouldn't the JVM take care of this?

Main.java:

package UI;

import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.ButtonBar;
import javafx.scene.layout.BorderPane;
import javafx.stage.Stage;

public class Main extends Application {

    @Override
    public void start(Stage primaryStage) throws Exception{
        primaryStage.setTitle("StopWatch");
        primaryStage.setScene(new Scene(getPane(), 400, 400));
        primaryStage.show();
    }


    private BorderPane getPane(){
        BorderPane pane = new BorderPane();

        ClockUI clockUI = new ClockUI();
        clockUI.setMinSize(200,200);
        pane.setCenter(clockUI);

        ButtonBar buttonBar = new ButtonBar();
        Button startButton = new Button("Start");
        startButton.setOnAction(e->clockUI.startClock());
        Button pauseButton = new Button("Stop");
        pauseButton.setOnAction(e->clockUI.stopClock());
        Button resetButton = new Button("Reset");
        resetButton.setOnAction(e->clockUI.resetClock());
        buttonBar.getButtons().addAll(startButton, pauseButton, resetButton);
        pane.setBottom(buttonBar);

        return pane;
    }

    public static void main(String[] args) {
        System.setProperty("prism.lcdtext","false");
        launch(args);
    }
}

ClockUI.java:

package UI;

import javafx.animation.*;
import javafx.scene.layout.StackPane;
import javafx.scene.paint.Color;
import javafx.scene.paint.Paint;
import javafx.scene.shape.Circle;
import javafx.scene.shape.Line;
import javafx.scene.transform.Rotate;
import javafx.util.Duration;

/**
 * Created by subhranil on 23/6/17.
 */
public class ClockUI extends StackPane {

    private final Rotate hourRotate;
    private final Rotate minuteRotate;
    private final Rotate secondRotate;
    private final Timeline hourTimeline;
    private final Timeline minuteTimeline;
    private final Timeline secondTimeline;
    private final ParallelTransition clockTransition;

    public ClockUI() {
        super();

        Line hourHand = getHand(80, Color.WHITE);
        hourRotate = getRotate(hourHand);
        hourTimeline = createRotateTimeline(Duration.hours(12), hourRotate);

        Line minuteHand = getHand(100, Color.WHITE);
        minuteRotate = getRotate(minuteHand);
        minuteTimeline = createRotateTimeline(Duration.minutes(60), minuteRotate);

        Line secondHand = getHand(90, Color.WHITE);
        secondRotate = getRotate(secondHand);
        secondTimeline = createRotateTimeline(Duration.seconds(60), secondRotate);

        clockTransition = new ParallelTransition(hourTimeline, minuteTimeline, secondTimeline);

        Circle back = new Circle(120);
        back.centerXProperty().bind(widthProperty().divide(2));
        back.centerYProperty().bind(heightProperty().divide(2));
        back.setStyle("-fx-fill: #555555");
        setStyle("-fx-background-color: #333333;");

        getChildren().addAll(back, hourHand, minuteHand, secondHand);
    }

    private Timeline createRotateTimeline(Duration duration, Rotate rotate) {
        Timeline timeline = new Timeline(30);
        timeline.getKeyFrames().add(new KeyFrame(duration, new KeyValue(rotate.angleProperty(), 360)));
        timeline.setCycleCount(Animation.INDEFINITE);
        return timeline;
    }

    public void startClock() {
        if (clockTransition.getStatus() != Animation.Status.RUNNING) {
            clockTransition.play();
        }
    }

    public void stopClock() {
        if (clockTransition.getStatus() == Animation.Status.RUNNING) {
            clockTransition.pause();
        }
    }

    public void resetClock() {
        stopClock();
        clockTransition.stop();
    }

    private Rotate getRotate(Line line){
        Rotate r = new Rotate(0);
        r.pivotXProperty().bind(line.startXProperty());
        r.pivotYProperty().bind(line.startYProperty());
        line.getTransforms().add(r);
        return r;
    }

    private Line getHand(int size, Paint color) {
        Line hand = new Line();
        hand.startXProperty().bind(widthProperty().divide(2));
        hand.startYProperty().bind(heightProperty().divide(2));
        hand.endXProperty().bind(widthProperty().divide(2));
        hand.endYProperty().bind(heightProperty().divide(2).subtract(size));
        hand.setStroke(color);
        hand.setStrokeWidth(3);

        return hand;
    }

}

信息:我尝试了各种各样的其他方法,比如运行 ExecutorService ,使用任务线程,但都产生相同的结果。

INFO : I've tried various other methods, like running an ExecutorService, using Task and Thread, but all yield same results.

推荐答案

试试这个,看看你是否遇到同样的问题。

Try this and see if you are having the same problem.


ClockGUI

ClockGUI



import javafx.scene.layout.*;
import javafx.scene.paint.*;
import javafx.scene.shape.*;
import javafx.scene.transform.*;

/**
 *
 * @author Sedrick
 */
public class ClockGUI {

    Circle clockFace;
    Line second;
    Line minute;
    Line hour;
    Rotate secondRotation;
    Rotate minuteRotation;
    Rotate hourRotation;
    AnchorPane currentClockFace;

    public ClockGUI()
    {
        currentClockFace = new AnchorPane();
        currentClockFace.setPrefSize(100, 100);

        clockFace = new Circle(100 / 2, 100 / 2, 100 / 2);
        clockFace.setStroke(Color.BLACK);
        clockFace.setFill(Color.TRANSPARENT);

        second = new Line(100 / 2, 100 / 2, 100 / 2, 100 / 2 - 40);
        secondRotation = new Rotate();
        secondRotation.pivotXProperty().bind(second.startXProperty());
        secondRotation.pivotYProperty().bind(second.startYProperty());
        second.getTransforms().add(secondRotation);

        minute = new Line(100 / 2, 100 / 2, 100 / 2, 100 / 2 - 30);
        minuteRotation = new Rotate();
        minuteRotation.pivotXProperty().bind(minute.startXProperty());
        minuteRotation.pivotYProperty().bind(minute.startYProperty());
        minute.getTransforms().add(minuteRotation);

        hour = new Line(100 / 2, 100 / 2, 100 / 2, 100 / 2 - 20);
        hourRotation = new Rotate();
        hourRotation.pivotXProperty().bind(hour.startXProperty());
        hourRotation.pivotYProperty().bind(hour.startYProperty());
        hour.getTransforms().add(hourRotation);

        currentClockFace.getChildren().addAll(clockFace, second, minute, hour);

    }

    public AnchorPane getCurrentClock()
    {
        return currentClockFace;
    }

    public void rotateSecondLine()
    {
        secondRotation.setAngle(secondRotation.getAngle() + 6);
    }

    public double getRotateSecondLine()
    {
        return secondRotation.getAngle();
    }

    public void setRotateSecond(double degree)
    {
        secondRotation.setAngle(degree);
    }

    public void rotateMinuteLine()
    {
        minuteRotation.setAngle(minuteRotation.getAngle() + 6);
    }

    public double getRotateMinuteLine()
    {
        return minuteRotation.getAngle();
    }

    public void setRotateMinute(double degree)
    {
        minuteRotation.setAngle(degree);
    }

    public void rotateHourLine()
    {
        hourRotation.setAngle(hourRotation.getAngle() + 6);
    }

    public double getRotateHourLine()
    {
        return hourRotation.getAngle();
    }

    public void setRotateHour(double degree)
    {
        hourRotation.setAngle(degree);
    }
}




Main

Main



import javafx.animation.*;
import javafx.application.*;
import javafx.event.*;
import javafx.scene.*;
import javafx.scene.control.*;
import javafx.scene.layout.*;
import javafx.stage.*;
import javafx.util.*;

/**
 *
 * @author Sedrick
 */
public class JavaFXApplication54 extends Application {

    @Override
    public void start(Stage primaryStage)
    {
        VBox root = new VBox();
        ClockGUI cgui = new ClockGUI();

        StackPane stackpane = new StackPane();
        stackpane.getChildren().add(cgui.getCurrentClock());
        root.getChildren().add(stackpane);

        Button btn = new Button("Rotate seconds");
        btn.setOnAction((event) -> {
            cgui.rotateSecondLine();
        });

        Button btn2 = new Button("Rotate minutes");
        btn2.setOnAction((event) -> {
            cgui.rotateMinuteLine();
        });

        Button btn3 = new Button("Rotate hours");
        btn3.setOnAction((event) -> {
            cgui.rotateHourLine();
        });

        root.getChildren().addAll(btn, btn2, btn3);
        Scene scene = new Scene(root, 300, 250);

        Timeline timeline = new Timeline();
        timeline.setCycleCount(Timeline.INDEFINITE);
        timeline.getKeyFrames().add(
                new KeyFrame(Duration.seconds(1),
                        new EventHandler() {
                    // KeyFrame event handler
                    @Override
                    public void handle(Event event)
                    {
                        System.out.println(cgui.getRotateSecondLine());
                        cgui.rotateSecondLine();
                        if (cgui.getRotateSecondLine() >= 360) {
                            cgui.setRotateSecond(0);
                            cgui.rotateMinuteLine();
                        }
                        if (cgui.getRotateMinuteLine() >= 360) {
                            cgui.setRotateMinute(0);
                            cgui.rotateHourLine();
                        }
                        if (cgui.getRotateHourLine() >= 360) {
                            cgui.setRotateHour(0);
                        }
                    }
                }
                ));
        timeline.playFromStart();
        primaryStage.setTitle("Hello World!");
        primaryStage.setScene(scene);
        primaryStage.show();
    }

    /**
     * @param args the command line arguments
     */
    public static void main(String[] args)
    {
        launch(args);
    }

}

这篇关于JavaFX无限期时间轴中的内存泄漏的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆