【发布时间】:2020-08-14 17:01:31
【问题描述】:
我目前正在编写一个 UCI 国际象棋引擎。在我的引擎内部,我有一个大的转置表,它将键映射到值。
在实现这一点时,我已经记住了内存,并且不想在表格中放置东西时创建新对象,所以我开始用空对象填充整个表格。
代码如下所示:
private TranspositionEntry[] entries;
private int size;
private int maxSize;
private long hashMask;
public TranspositionTable(int keyBits){
this.maxSize = (int)(Math.pow(2, keyBits));
this.hashMask = maxSize - 1;
this.entries = new TranspositionEntry[maxSize];
for(int i = 0; i < maxSize; i++){
this.entries[i] = new TranspositionEntry(0,0,0,0,0, new Move(0, 0, 0, 0));
}
}
private int index(long zobrist){
return (int)(zobrist & hashMask);
}
public boolean contains(long key){
int index = index(key);
return entries[index].getZobrist() != 0;
}
public void clear(){
for(int i = 0; i < maxSize; i++){
this.entries[i].setZobrist(0);
}
}
public int size(){
return size;
}
public TranspositionEntry get(long key){
System.out.println("I was called");
int index = index(key);
if(entries[index].getZobrist() == 0) return null;
return entries[index];
}
public void put(long key, double eval, int depthLeft, int node_tpe, int color, Move move){
int index = index(key);
System.out.println("I was called");
TranspositionEntry en = entries[index];
if(en.getZobrist() == 0) size++;
en.setVal(eval);
en.setDepthLeft(depthLeft);
en.setNode_type(node_tpe);
en.setColor(color);
en.getBestMove().setType(move.getType());
en.getBestMove().setFrom(move.getFrom());
en.getBestMove().setTo(move.getTo());
en.getBestMove().setPieceFrom(move.getPieceFrom());
en.getBestMove().setPieceTo(move.getPieceTo());
}
这是一个非常非常基本的哈希算法,但这与这个问题无关。 我通过运行这段代码测试了这个对象消耗了多少内存:
InstrumentationAgent.printMemoryOverview();
TranspositionTable<TranspositionEntry> entryTranspositionTable = new TranspositionTable<>(20);
InstrumentationAgent.printMemoryOverview();
System.out.println(entryTranspositionTable);
这给了我以下输出:
Used Memory : 7 MB
Free Memory : 483 MB
Total Memory : 491 MB
Max Memory : 7268 MB
Used Memory : 100 MB
Free Memory : 390 MB
Total Memory : 491 MB
Max Memory : 7268 MB
ai.tools.transpositions.TranspositionTable@1b6d3586
所以你可以看到这个表本身确实消耗了大约100MB 的内存。
现在有趣的部分来了:
当我运行我的代码来寻找给定位置的最佳移动时,我 通常首先创建转置表(或清除它,如果它 已经存在)。但我禁用了对转置的 ALL 访问
size()除外。如上所示,表中有get/put方法 带有VisualVM 在搜索位置时给我这个内存输出 转置表已在开始时创建但未使用 随时。
如您所见,内存使用量一开始就很高,然后收敛到相当低的水平。
我最初认为搜索本身在开始时会消耗这么多内存(这没有意义)。所以我运行了完全相同代码,除了this._transpositionTable = new TranspositionTable(20);
输出如下:
如您所见,搜索本身不会导致这些内存峰值。
所以我的问题是:
- 为什么纯粹存在未使用的数组会导致这些内存峰值,尤其是仅在代码开头
- 这个问题有解决办法吗?
解决这个问题对我来说非常重要,因为在测试时,我需要同时运行多个引擎,所以内存是个问题。我很高兴得到任何帮助或建议!
您好, 芬兰人
编辑 1:
添加转置入口代码:
private double val;
private long zobrist;
private int depthLeft;
private int node_type;
private int color;
private Move bestMove;
public TranspositionEntry(long zobrist, double val, int depthLeft, int node_type, int color, Move bestMove) {
this.val = val;
this.zobrist = zobrist;
this.depthLeft = depthLeft;
this.node_type = node_type;
this.color = color;
this.bestMove = bestMove;
}
编辑 2
我找到了解决这个问题的方法。
如果从一开始就限制了最大堆空间,则似乎不会出现尖峰。
我添加了xmx1024M,这似乎解决了问题。
【问题讨论】:
-
表项的创建是在表的构造函数中完成的
-
另外,为什么这会使用超过 1G 的 RAM?
-
``` public TranspositionEntry(long zobrist, double val, int depthLeft, int node_type, int color, Move bestMove) { this.val = val; this.zobrist = zobrist; this.depthLeft = depthLeft; this.node_type = node_type; this.color = 颜色; this.bestMove = 最佳移动; } ```
-
实际上只是复制这些值
-
不要将代码放在 cmets 中,它不可读。只需编辑问题。
标签: java arrays memory heap-memory