所以我正在尝试为黑白棋游戏实现蒙特卡罗搜索树。我有一个根节点和子节点,其中“x”是“y”的子节点,如果您可以在一次合法的移动中从“y”移动到“x”。
在每个节点上,我存储一个“Board”对象,其中包含所有棋盘信息,例如每个图 block 的值。我遇到的第一个问题是,如果我更改子节点的板对象,它也会更改父节点的值。我通过为每个子节点创建一个"new"Board 对象来修复此问题,但这导致当我运行模拟几千次时使用过多的内存,以至于内存不足。
我只是想知道是否有一种方法可以更改子节点中的板信息而不更改父节点的板信息,或者是否有更好的方法在每个节点存储板信息而不是创建每个节点都有一个新的 Board 对象。
如果有任何需要澄清的地方,请在下面评论,感谢您的阅读!
编辑:
for (int x = 0; x < numberOfChildren; x += 1) {
// Resets *currentBoard to the same state as the node being expanded
Board *currentBoard = nodeToExpand->getCurrentBoard();
// Retrives the board value information
int** temporaryBoardValues = currentBoard->getBoardValues();
// Makes a new board object with the previous parameters
Board *temporaryBoard = new Board(blockSize, boardSize, offset);
// Sets the new board values to the same as the old ones
temporaryBoard->setBoardValues(temporaryBoardValues);
// Creates a clone of that board state
// Board *temporaryBoard = cloneBoard(*currentBoard);
// Creates a node with the cloned board state, setting the parent to be the node being expanded.
// Assigns it one of the available moves
// Produces the array of child nodes
myChildren[x] = new Node(nodeToExpand, temporaryBoard, availableMoves[x], currentPlayer);
//delete temporaryBoard;
}
小代码片段。这是我创建一个新的 Board 对象的部分,该对象耗尽了所有内存。
最佳答案
蒙特卡罗树搜索 (MCTS) 的典型实现不使用任何技巧来明确避免内存不足。理论上,如果继续模拟,确实会耗尽内存,但这通常需要的不仅仅是您在 OP 中提到的几千次模拟。
现在,MCTS 的大多数实现每次模拟仅将树扩展一个节点。您发布的代码看起来像是在每次模拟时向树添加 b
节点,其中 b
是分支因子(子级数)。所以这是你可以考虑改变的事情。
此外,您可以查看在 Board 类中存储的内容,并确保您确实只拥有必要的内容,仅此而已。只是游戏状态的数据,仅此而已。例如,确保其中没有任何仅 GUI 所需的数据(这是我几年前犯的一个错误)。
如果你在研究了这两点后仍然存在内存问题,你可以考虑 jaggedSpire 评论的建议。您可以存储移动而不是棋盘状态,并在模拟中运行节点时重新构建棋盘状态。这将显着减少内存消耗,但也会增加每次模拟的处理时间。如果您每回合的思考时间有限,这可能会导致玩家实力较弱。
最后,考虑到您正在使用我在您发布的代码中看到的new
操作进行手动内存管理,您总是有可能忘记匹配的delete
> 某处存在内存泄漏。如果在研究了上述几点后,只有几千次模拟仍然存在内存问题,这是最有可能的原因,因为 MCTS 确实不应该遇到内存问题,直到您达到比几千更高的模拟计数。
关于c++ - 由于创建新对象,C++ 中内存不足,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40382567/