我有以下Java方法:
static Board board;
static int[][] POSSIBLE_PLAYS; // [262143][0 - 81]
public static void playSingleBoard() {
int subBoard = board.subBoards[board.boardIndex];
int randomMoveId = generateRandomInt(POSSIBLE_PLAYS[subBoard].length);
board.play(board.boardIndex, POSSIBLE_PLAYS[subBoard][randomMoveId]);
}访问的数组在运行时不会更改。方法总是由同一个线程调用。board.boardIndex可能从改为8,共有9 subBoards。
在VisualVM中,以执行2 228 212次数(Total )的方法结束:
Self Time 27.9%
Board.play(int, int) 24.6%
MainClass.generateRnadomInt(int) 8.7%我想知道的是,自执行的27.9% (999ms /2189 is )从何而来?我最初认为分配2 int可以减慢方法的速度,因此我尝试了以下方法:
public static void playSingleBoard() {
board.play(
board.boardIndex,
POSSIBLE_PLAYS[board.subBoards[board.boardIndex]]
[generateRandomInt(POSSIBLE_PLAYS[board.subBoards[board.boardIndex]].length)]
);
}但是最后得到了类似的结果,我不知道这个自我执行的时间会是什么。现在是GC时间吗?内存访问?
我已经尝试过这里提到的JVM选项,=>,VisualVM -奇怪的自我时间和with。
发布于 2021-06-20 17:23:25
首先,Visual (以及许多其他基于safepoint的分析器)是固有的误导。尝试使用不受safepoint偏见影响的轮廓仪。例如,异步分析器不仅可以显示方法,还可以显示花费最多CPU时间的特定行/字节码。
其次,在您的示例中,playSingleBoard可能确实需要相对较长的时间。即使没有分析器,我也可以看出,这里最昂贵的操作是大量的数组访问。
RAM是新磁盘。内存访问是不自由的,特别是随机访问。特别是当数据集太大,无法适应CPU缓存。此外,Java中的数组访问需要进行边界检查。而且,在Java中没有真正的二维数组,它们是数组的数组。
这意味着,像POSSIBLE_PLAYS[subBoard][randomMoveId]这样的表达式至少会导致5次内存读取和2次边界检查。而且每次出现L3缓存丢失(在您的情况下可能是大型数组),这将导致~50 ns 潜伏期 -足够时间执行100个算术操作否则。
https://stackoverflow.com/questions/68056651
复制相似问题