Java性能优化

时间:2014-07-05 12:13:03

标签: java performance

对于JOGL游戏我得到非常低的fps,现在通过一些测试我发现问题不在JOGL部分,而是在纯Java计算中。我需要定义很多浮点变量,它占用了90%的时间。

我测试了45个浮点变量,其中只有16个得到初始值。其余的只是float z1; float z2;等。根据System.currentTimeMillis(),这需要大约5-10毫秒。

但是这个带有45个浮点数的代码是一个双循环调用的方法。总共这种方法被称为49次(7 * 7)。所有这些都在JOGL方法中用于在JFrame中绘制游戏,但由于这么多浮点变量,它总共需要100ms,这意味着只有10fps。

基本上问题是我必须初始化45 * 49 = 2205浮点数。有没有办法优化它以获得更好的fps?

例如,double会比float更快吗?或者首先在循环外定义变量,并在循环内给它们值?有谁知道让这段代码运行得更快的方法?非常感谢。

修改

根据要求,这是源代码:

for (int x = -4; x < 3; x++) { // Loops 7 times
    for (int y = -4; y < 3; y++) { // Loops 7 times
        long t1 = System.currentTimeMillis();
        float z0  = terrain.getHeight(x-1, y-1); // Simple method, but takes up about half of the time
        float z1  = terrain.getHeight(x  , y-1);
        float z3  = terrain.getHeight(x+1, y-1);
        float z4  = terrain.getHeight(x+2, y-1);
        float z5  = terrain.getHeight(x-1, y  );
        float z6  = terrain.getHeight(x  , y  );
        float z7;
        float z8;
        float z9;
        float z10 = terrain.getHeight(x+1, y  );
        float z11 = terrain.getHeight(x+2, y  );
        float z12;
        float z13;
        float z14;
        float z15;
        float z16;
        float z17;
        float z18;
        float z19;
        float z20;
        float z21;
        float z22;
        float z23;
        float z24;
        float z25;
        float z26;
        float z27;
        float z28;
        float z29;
        float z30;
        float z31;
        float z32;
        float z33 = terrain.getHeight(x-1, y+1);
        float z34 = terrain.getHeight(x  , y+1);
        float z35;
        float z36;
        float z37;
        float z38 = terrain.getHeight(x+1, y+1);
        float z39 = terrain.getHeight(x+2, y+1);
        float z40 = terrain.getHeight(x-1, y+2);
        float z41 = terrain.getHeight(x  , y+2);
        float z43 = terrain.getHeight(x+1, y+2);
        float z44 = terrain.getHeight(x+2, y+2);
        t1 = System.currentTimeMillis() - t1;
        // Some other code where I use these variables.
        // Takes between 0-1 ms in total.
    }
}

修改

我现在测试了getHeight()方法,它占用了大约一半的时间。使用此方法的七个变量加起来大约为5毫秒,其中总数为10.以下是getHeight()中使用的代码:

public float getHeight(float x, float y) {
    long t1 = System.currentTimeMillis();
    Coordinate c = new Coordinate(x, y);
    for (Entry<Coordinate, Float> e : heightMap.entrySet()) { // heightMap = HashMap<Coordinate, Float>
        if (e.getKey().x == c.x && e.getKey().y == c.y) {
            System.out.println("getHeight: " + (System.currentTimeMillis() - t1) + " ms");
            return e.getValue();
        }
    }
    return 0f;
}

Coordinate是我自己创建的一个类,它有一个带有两个x和y浮点参数的构造函数,并将它们全局保存在类本身。

我之所以不使用heightMap.get(c),是因为它总是抛出NullPointerException,而上面给出的代码永远不会到达return 0f;的最后一行。

修改

在[link](Why are custom objects not equivalent keys for a HashMap?)问题中找到问题的解决方案,即我必须将public boolean equals(Object other)public int hashCode()添加到我的自定义Coordinate类。现在getHeight方法可以使用heightMap.get(c),它可以删除那里的循环并使程序更快。总数(有49个循环)现在大约需要1毫秒。

2 个答案:

答案 0 :(得分:1)

请注意,某些操作系统必须使用全屏独占模式才能为您提供足够的资源。

在循环之外定义变量无济于事,因为Java优化了代码并在循环中定义变量实际上提供了Java提示来提高性能。我认为(我只能猜测,因为你没有发布任何代码),你可以考虑使用long数组。它们非常有效地在循环中工作,并且它们也会在您的内存中一个接一个地分配,因此可以有效地使用缓存。

对我而言,填充2025个长度略高于 1毫秒,包括调用random.nextLong()方法。

public Long fillLongs(int numberofLongs) {

    long[] longs = new long[numberofLongs];
    Random r = new Random();

    long start = System.currentTimeMillis();

    for (long l : longs) {
        l = r.nextLong();
    }

    long end = System.currentTimeMillis();

    return end - start;

}

使用并行流,此任务花费的时间更少。通常不到1毫秒。

public Long fillLongs(int numberofLongs) {

    Long[] longs = new Long[numberofLongs];
    List<Long> longList = Arrays.asList(longs);
    Random r = new Random();

    long start = System.currentTimeMillis();

    longList.parallelStream().forEach(l -> {
        l = r.nextLong();
    });

    long end = System.currentTimeMillis();

    return end - start;

}

答案 1 :(得分:-1)

对于Java中的高性能计算,您可能会考虑使用usi JNI(Java Native Interface) - 尽管它需要C ++知识。如需快速入门,请查看here