为什么这个Java应用程序在Mac而不是PC上运行缓慢?

时间:2014-04-04 17:53:07

标签: java macos

我使用Java创建了一个应用程序,它在Windows平台上运行顺畅。但是,当我使用4960HQ在我的Macbook Pro Retina 15'上进行测试时,显示的帧速率要低得多。

我已经将程序编码为以60fps的恒定速度运行动画,控制台显示在Mac和Windows上都绘制了60fps。但是,Mac上的程序看起来像是以8-8fps运行。

是否有适合Mac的特殊编码方法?或者java根本没有针对Mac OSX进行优化?

代码的最小工作样本:

    long framerate = 1000 / 60;
    // time the frame began
    long frameStart;
    // number of frames counted this second
    long frameCount = 0;
    // time elapsed during one frame
    long elapsedTime;
    // accumulates elapsed time over multiple frames
    long totalElapsedTime = 0;
    // the actual calculated framerate reported

    while(true){
        frameStart = System.currentTimeMillis();

        world.moveBG(3);

        // calculate the time it took to render the frame
            elapsedTime = System.currentTimeMillis() - frameStart;
            // sync the framerate
            try {
                // make sure framerate milliseconds have passed this frame
                if (elapsedTime < framerate) {
                    Thread.sleep(framerate - elapsedTime);
                } else {
                    // don't starve the garbage collector
                    Thread.sleep(5);
                }
            } catch (InterruptedException e) {
                break;
            }
            ++frameCount;
            totalElapsedTime += (System.currentTimeMillis() - frameStart);
            if (totalElapsedTime > 1000) {
                reportedFramerate = (long) ((double) frameCount
                        / (double) totalElapsedTime * 1000.0);
                // show the framerate in the applet status window
                System.out.println("fps: " + reportedFramerate);
                // repaint();
                frameCount = 0;
                totalElapsedTime = 0;
            }
    }

这段代码处理控制fps,现在设置为60fps。 world.moveBG(3)以每帧3个像素的速度在屏幕上移动和图像(由于它是一个小图像,因此不应该是性能密集型的)。 Mac以明显的10fps运行,窗口平滑60.两台机器上的控制台显示正在绘制60fps。

要澄清一下,并不是说Mac上的屏幕上的图像移动速度比Windows慢,而是Mac上的移动速度非常不稳定

1 个答案:

答案 0 :(得分:1)

下一个代码启动执行程序并安排任务以完成帧速率。 在Windows上运行3秒钟,我的最后一条跟踪指示了179个任务,因此几乎每秒需要执行60个任务。

尝试使用此代码并告知我是否可以提高您的效果:

package com.nosolojava.test;

import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.logging.Level;
import java.util.logging.Logger;

public class FrameRateExecutor {

private final Logger logger = Logger.getLogger(this.getClass().getCanonicalName());

final static long framerate = 1000 / 60;

// number of frames counted this second
AtomicInteger frameCount = new AtomicInteger(0);

ScheduledExecutorService executor;
private volatile AtomicBoolean running = new AtomicBoolean(false);

class Task implements Runnable {
    private final long lastTaskTimeStamp;

    public Task() {
        super();
        //get creation time so we can calculate delay after
        this.lastTaskTimeStamp = System.currentTimeMillis();
    }

    public void run() {
        // TODO implement logic
        logger.log(
                Level.INFO,
                String.format("Do something, framecount: %02d %d", frameCount.addAndGet(1),
                        System.currentTimeMillis()));

        //calculate when to execute next task and submit
        long currentTime = System.currentTimeMillis();
        long elapsed = currentTime - lastTaskTimeStamp;
        long delay = (framerate - elapsed) +framerate;

        logger.log(Level.INFO, String.format("elapsed %04d delay %04d", elapsed, delay));

        //check finish condition 
        if (running.get()) {
            executor.schedule(new Task(), delay, TimeUnit.MILLISECONDS);
        }
    }
};

public void stop() {
    running.set(false);
    executor.shutdown();

    try {
        executor.awaitTermination(3, TimeUnit.SECONDS);
    } catch (InterruptedException e) {
        logger.log(Level.SEVERE, "Error stopping executor", e);
    }

}

public void start() {

    //check if is already up
    if (this.running.compareAndSet(false, true)) {
        //init scheduled executor
        executor = new ScheduledThreadPoolExecutor(1);

        //start first task 
        executor.execute(new Task());
    }
}

public static void main(String[] args) throws InterruptedException {
    FrameRateExecutor frameExecutor = new FrameRateExecutor();

    frameExecutor.start();

    Thread.sleep(3000);
    frameExecutor.stop();

}

}