JAVA - 构造函数中的数组副本在大量调用后意外地变慢

时间:2018-04-05 14:36:46

标签: java arrays monte-carlo-tree-search

我目前正在尝试提高Java代码的性能。在挖掘了一下以查看需要优化的地方之后,我最终得到了以下设置(为了清晰起见而简化)。

Board构造函数被称为很多次(~200k到2M):

public Board(Board board) {
    long now = System.currentTimeMillis();

    this.macroBoard = new int[9];
    int [] boardToCopy = board.getMacroBoard();
    for (int i = 0; i < 9; i++){
        this.macroBoard[i] = boardToCopy[i];
    }

    long duration = System.currentTimeMillis() - now;
    if (duration > THRESHOLD){
        System.err.println(duration);
    }
}

在另一堂课中:

long end = System.currentTimeMillis() + SIMULATION_DURATION;
while (System.currentTimeMillis() < end) {
    ...
    ...
    Board board = new Board(otherBoard);
    ... 
    ...
}

结果让我感到困惑。事实上我发现了两件事:

  1. SIMULATION_DURATION越大, max(持续时间)越大;
  2. 当SIMULATION_DURATION = 10s时, max(持续时间)的值可以达到2s(是秒,没有拼写错误)。如果SIMULATION_DURATION = 100ms,我观察到 max(持续时间)大约30ms。
  3. 我的问题如下:

    1. 9整数数组的副本如何花这么长时间?
    2. 为什么持续时间 99%的时间小于0.1ms而剩下的1%真的很高?
    3. 为什么它取决于SIMULATION_DURATION的价值?
    4. 我使用System.currentTimeMillis()为这种基准测试时犯了错误,因此结果完全不准确?
    5. 当我创建大量Board对象时,GC是否涉及这种奇怪的行为?

2 个答案:

答案 0 :(得分:4)

听起来你的虚拟机内存不足,正在尝试GC,以便它可以为新阵列分配内存。您可以在此链接中找到信息以启用GC日志记录,并获取有关VM的GCing行为的更多详细信息:https://dzone.com/articles/enabling-and-analysing-the-garbage-collection-log

另外,我建议使用System.nanoTime()来衡量效果。有关详细信息:System.currentTimeMillis vs System.nanoTime

直接回答问题:

9整数数组的副本如何花费这么长时间?

绝对不应该。检查GC日志以确认GC正在减慢VM的速度。

为什么99%的时间内持续时间小于0.1ms而剩余的1%时间确实很高?

99%的情况下,您的内存不足,因此为新的Board对象分配空间没有问题。

为什么它取决于SIMULATION_DURATION的值?

SIMULATION_DURATION的值直接控制Board个对象的数量。

我使用System.currentTimeMillis()在这种基准测试中犯了错误,因此结果完全不准确吗?

检查上面其他堆栈溢出问题的链接。

当我创建大量Board对象时,GC是否涉及这种奇怪的行为?

检查上面的答案。

答案 1 :(得分:1)

pranavmalhotra的答案比我的更有价值,但肯定会有改进。

有关

this.macroBoard = new int[9];
int[] boardToCopy = board.getMacroBoard();
for (int i = 0; i < 9; i++){
    this.macroBoard[i] = boardToCopy[i];
}

第一次优化将是

this.macroBoard = new int[9];
int[] boardToCopy = board.getMacroBoard();
System.arraycopy(boardToCopy, 0, macroBoard, 0, 9);

甚至:

int[] boardToCopy = board.getMacroBoard();
this.macroBoard = Arrays.copyOf(boardToCopy, 9);

优化可以采取多种形式。如果电路板整数范围为0 .. 127,则为1 可以将每7位int放入一个long中,因为7 * 9 = 63&lt; 64位长。 long是基本类型。