Java节省2d瓦片:for循环在每次迭代时变慢,最多5秒,10000次迭代

时间:2017-11-16 15:14:18

标签: java arrays for-loop iteration 2d-games

我目前正在开发基于瓷砖的2D游戏。目前,我正在编写一个拯救整个世界的过程。一般来说,世界是10000 x 10 = 1.100.000块大。显然,它不应该是java的问题,但它是。

这是我的循环:

Material[][] blocks = g.gameState.getLevel().tiles;
int y = 0;
int blocksHor = g.gameState.getLevel().getBlocksHor();

for(int x = 0; x < blocksHor; x++) {

    world += blocks[y][x] + " ";

    if(x >= blocksHor - 1) {
        x = 0;
        y++;
        System.out.println("LAYER " + y + " => " + (System.currentTimeMillis() - now) + " ms");
        now = System.currentTimeMillis();
    }
}

循环有点难以理解,但我已经尝试在任何可能的地方进行优化。这是控制台输出:

LAYER 1 => 86 ms
LAYER 2 => 276 ms
LAYER 3 => 424 ms
LAYER 4 => 618 ms
LAYER 5 => 561 ms
LAYER 6 => 541 ms
LAYER 7 => 755 ms
LAYER 8 => 885 ms
LAYER 9 => 1036 ms

这些过程最多需要50秒甚至更长时间。

这个循环出了什么问题?老实说,我不知道应该如何解决这个问题。

谢谢:) -phil

1 个答案:

答案 0 :(得分:2)

如果您提供的代码确实代表了您的问题,则问题很可能在

world += blocks[y][x] + " ";

有几个性能问题。首先,world必须具有String类型,而String是不可变的。因此,每当您通过+运算符连接它们时,必须创建一个新的运算符来保存结果。在每次执行该语句时,您至少要执行两次这样做,总共产生超过2M的垃圾对象,这些垃圾对象最终必须被收集。

此外,world的中间值在大小上稳定增加,因此所有临时消耗的组合内存与块总数的平方成比例。即使每个块的字符串值只有一个字符长,这也会占用大量内存。你最终会遇到严重的垃圾收集问题,而且随着你的继续,它们确实会变得越来越糟。

作为改善此问题的第一次尝试,您可以考虑将数据累积到StringBuilder而不是String

StringBuilder worldBuilder = new StringBuilder();

// ...

worldBuilder.append(blocks[y][x]).append(' ');

这应该通过创建更少的垃圾来显着缓解GC问题,但是你仍然需要一个非常大的对象来保持整个状态。因此,我还建议将数据累积到较小的块中,然后输出它们,而不是在输出任何内容之前在内存中构造整个表示。

您可能还想查看Material.toString()的实现,因为如果它也通过执行字符串连接产生大量垃圾,那么这将放大问题。