Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/358.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
在JavaFX中,任何类型的动画或时间线都会使用过多的CPU_Java_Javafx_Javafx 8 - Fatal编程技术网

在JavaFX中,任何类型的动画或时间线都会使用过多的CPU

在JavaFX中,任何类型的动画或时间线都会使用过多的CPU,java,javafx,javafx-8,Java,Javafx,Javafx 8,我正在使用JDK 8.0附带的JavaFx,在MacBook Pro上使用2,4 GHz Intel Core 2 Duo处理器和4GB RAM 我有一个奇怪的行为,使用以下类: import com.sun.javafx.perf.PerformanceTracker; import javafx.animation.AnimationTimer; import javafx.application.Application; import javafx.event.ActionEvent;

我正在使用JDK 8.0附带的JavaFx,在MacBook Pro上使用2,4 GHz Intel Core 2 Duo处理器和4GB RAM

我有一个奇怪的行为,使用以下类:

import com.sun.javafx.perf.PerformanceTracker;

import javafx.animation.AnimationTimer;
import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.layout.Pane;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;

public class HelloWorld extends Application {
    private static PerformanceTracker tracker;
    public static void main(String[] args) {
        launch(args);
    }

    @Override
    public void start(Stage primaryStage) {
        primaryStage.setTitle("Hello World!");
        Button btn = new Button();
        btn.setText("Say 'Hello World'");
        btn.setOnAction(new EventHandler<ActionEvent>() {

            @Override
            public void handle(ActionEvent event) {
                System.out.println("Hello World!");
            }
        });

        StackPane root = new StackPane();
        root.getChildren().add(btn);
        Scene scene= new Scene(root, 300, 250);
        primaryStage.setScene(scene);
        primaryStage.show();


        Label label1 = new Label();
        Label label2 = new Label();
        ((Pane)root).getChildren().addAll(label1, label2);

        scene.setOnKeyPressed((e)->{
            label2.setText(label1.getText());
        });



        tracker = PerformanceTracker.getSceneTracker(scene);
        AnimationTimer frameRateMeter = new AnimationTimer() {

            @Override
            public void handle(long now) {
                label1.setText(String.format("Current frame rate: %.3f fps", getFPS()));
            }
        };

        //frameRateMeter.start();


    }

    private float getFPS () {
        float fps = tracker.getAverageFPS();
        tracker.resetAverageFPS();
        return fps;
    }
}
我得到相同的代码使用CPU的比例从20%到40%

这只是一个例子,但是,我编写的应用程序,注释掉上面的行,使用大约40%的CPU运行,删除注释运行的CPU接近100%

这正常吗?我注意到,添加任何连续执行的时间轴(也是非常简单的时间轴),会产生荒谬的CPU使用

在JavaFX中使用动画真的很昂贵,还是我错过了一些东西


非常感谢您的帮助。

我认为您正在非常频繁地更新标签中的FPS值:

AnimationTimer类允许创建一个计时器,当它处于活动状态时,在每一帧中调用该计时器

当您在
label1
中更新文本时,JavaFX会一次又一次地绘制新帧。您可以轻松检查:将FPS写入标准输出,而不是
label1

...
System.out.println(String.format("Current frame rate: %.3f fps", tracker.getAverageFPS()));
// label1.setText(String.format("Current frame rate: %.3f fps", tracker.getAverageFPS()));
...
在这种情况下,您应该看到较少的FPS速率

因此,尝试每一秒或半秒使用任何Java/JavaFX计时器更新FPS值,即:

Timeline timeline = new Timeline(new KeyFrame(Duration.millis(500), event -> {
    label1.setText(String.format("Current frame rate: %.3f fps", tracker.getAverageFPS()));
}));
timeline.setCycleCount(Animation.INDEFINITE);
timeline.play();

在我的macOS上,平均CPU值约为1.8-2%。

这里有一个简单的方法可以从
AnimationTimer
计算FPS[每秒帧数]:

/**
 * AnimationTimer .
 *
 * @author GOXR3PLUS
 */
public class PaintService extends AnimationTimer {

    /** The next second. */
    long nextSecond = 0L;

    /** The Constant ONE_SECOND_NANOS. */
    private static final long ONE_SECOND_NANOS = 1_000_000_000L;
    /**
     * When this property is <b>true</b> the AnimationTimer is running
     */
    private volatile SimpleBooleanProperty running = new SimpleBooleanProperty(false);


    @Override
    public void start() {
        nextSecond = 0L;
        super.start();
        running.set(true);
    }

    @Override
    public void stop() {
        super.stop();
        running.set(false);
    }

    /**
     * @return True if AnimationTimer is running
     */
    public boolean isRunning() {
        return running.get();
    }

    /**
     * @return Running Property
     */
    public SimpleBooleanProperty runningProperty() {
        return running;
    }


    @Override
    public void handle(long nanos) {

        // -- Show FPS if necessary.
        if (true) { //originally i had a variable (showFPS) here

            framesPerSecond++;

            // Check for 1 second passed
            if (nanos >= nextSecond) {
                fps = framesPerSecond;
                framesPerSecond = 0;
                nextSecond = nanos + ONE_SECOND_NANOS;
            }


            label.setText("FPS: " + fps);
        }


    }

}
/**
*动画定时器。
*
*@author GOXR3PLUS
*/
公共类PaintService扩展了AnimationTimer{
/**下一秒*/
长下一秒=0升;
/**常数为1秒纳米*/
专用静态最终长1_秒_纳米=1_000_000_000L;
/**
*当此属性为true时,AnimationTimer正在运行
*/
私有易失性SimpleBoleAnProperty running=新SimpleBoleAnProperty(false);
@凌驾
公开作废开始(){
下一秒=0升;
super.start();
正在运行。设置(true);
}
@凌驾
公共停车场(){
super.stop();
正在运行。设置(false);
}
/**
*@如果AnimationTimer正在运行,则返回True
*/
公共布尔值正在运行(){
返回running.get();
}
/**
*@return运行属性
*/
公共SimpleBoleAnProperty runningProperty(){
返回运行;
}
@凌驾
公共空心把手(长纳米){
//--如有必要,显示FPS。
如果(true){//最初我在这里有一个变量(showFPS)
framesPerSecond++;
//检查是否有1秒通过
如果(毫微秒>=下一秒){
fps=帧秒;
framesPerSecond=0;
下一秒=纳米+一秒纳米;
}
label.setText(“FPS:+FPS”);
}
}
}

Hi Maxim,谢谢您的回复,但每秒更新FPS有什么意义?FPS是每秒的帧数。。。顺便说一句,你有哪种Mac?重点是降低CPU使用率:)你不应该每毫秒更新标签中的文本,因为这会增加CPU使用率。只需每秒更新一次。嗨,马克西姆,我现在知道了,我已经接受了你的正确答案。谢谢;)马克西姆答案的密码是一个很好的解决方案。使用
com.sun…
对于未来的应用程序来说似乎有风险,因为库可能会被删除。您可以使用其他方法计算每秒帧数,使用2个内部变量。顺便说一句,如果你愿意的话,我会为你添加一个答案。谢谢@GOXR3PLUS,我将非常感谢你的回答。我还必须强调,使用每10毫秒更新一次的计时器或时间线,会大大提高CPU的使用率。也许我的机器不是最先进的(Core 2 Duo和4GB内存),但从理论上讲,它应该能够轻松地管理此类操作,或者不是?你应该每1秒更新一次标签。不需要时间线真的。。。w8
AnimationTimer
每秒更新60次(实际上它尝试这样做)。别担心,我一回到电脑就会发布额外的答案。也许一天之内。@navy1978什么都没有我的朋友。。。这就是我在应用程序中使用的代码:)
/**
 * AnimationTimer .
 *
 * @author GOXR3PLUS
 */
public class PaintService extends AnimationTimer {

    /** The next second. */
    long nextSecond = 0L;

    /** The Constant ONE_SECOND_NANOS. */
    private static final long ONE_SECOND_NANOS = 1_000_000_000L;
    /**
     * When this property is <b>true</b> the AnimationTimer is running
     */
    private volatile SimpleBooleanProperty running = new SimpleBooleanProperty(false);


    @Override
    public void start() {
        nextSecond = 0L;
        super.start();
        running.set(true);
    }

    @Override
    public void stop() {
        super.stop();
        running.set(false);
    }

    /**
     * @return True if AnimationTimer is running
     */
    public boolean isRunning() {
        return running.get();
    }

    /**
     * @return Running Property
     */
    public SimpleBooleanProperty runningProperty() {
        return running;
    }


    @Override
    public void handle(long nanos) {

        // -- Show FPS if necessary.
        if (true) { //originally i had a variable (showFPS) here

            framesPerSecond++;

            // Check for 1 second passed
            if (nanos >= nextSecond) {
                fps = framesPerSecond;
                framesPerSecond = 0;
                nextSecond = nanos + ONE_SECOND_NANOS;
            }


            label.setText("FPS: " + fps);
        }


    }

}