【问题标题】:Java saving 2d tiles: for loop getting slower with each iteration up to 5 seconds for 10000 iterationsJava保存2D块:对于循环,每次迭代的循环速度较慢,可达5秒,可用于10000次迭代
【发布时间】:2018-04-30 04:45:44
【问题描述】:

我目前正在开发基于图块的 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 秒或更长时间。

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

谢谢你:) -菲尔

【问题讨论】:

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


【解决方案1】:

如果您提供的代码确实代表了您的问题,那么问题很可能发生在

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

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

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

作为改进这一点的第一次尝试,您可以考虑将数据累积到 StringBuilder 而不是 String

StringBuilder worldBuilder = new StringBuilder();

// ...

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

这应该会通过创建更少的垃圾来显着缓解 GC 问题,但您最终仍然需要一个相当大的对象来保存整个状态。因此,我还建议将数据累积成更小的块,随时输出,而不是在输出任何内容之前在内存中构建整个表示。

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

【讨论】:

  • 哦,谢谢!这是一个很好的解决方案,效果也很好
  • 大声笑,现在这个过程在 1 毫秒内运行。囧
猜你喜欢
  • 2018-02-13
  • 2020-01-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-03-15
相关资源
最近更新 更多