Я сейчас пишу шахматный движок 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());
}
Это очень очень простой c алгоритм хеширования, но он не имеет отношения к этому вопросу , Я проверил, сколько памяти занимает этот объект, запустив этот код:
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
методы с print
-составлением, и они не вызываются в любое время.
VisualVM выдает мне этот вывод памяти при поиске позиции, где транспонирование Таблица была создана при запуске, но не используется в любое время.
Как видите, использование памяти очень высокое для начала с и сходится к довольно низкому уровню. Сначала я думал, что сам поиск потребляет столько памяти в начале (что не имеет смысла). Поэтому я запустил точно такой же код , за исключением this._transpositionTable = new TranspositionTable(20);
Вывод выглядит так:
Как видите, сам поиск делает НЕ причиной этих скачков памяти.
Поэтому мои вопросы таковы:
- Почему существует чистое существование неиспользуемого массива вызывая эти всплески памяти и особенно только в начале кода
- Есть ли решение этой проблемы?
Это очень важно для меня, чтобы решить эту проблему, потому что при тестировании, Мне нужно запустить много двигателей одновременно, поэтому проблема с памятью. Я очень очень рад за любую помощь или совет!
Привет, Финн
РЕДАКТИРОВАТЬ 1:
Добавление кода TranspositionEntry:
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
, и это, кажется, решить проблему.