C++ C+中的内存不足+;因为制造新的物体

C++ C+中的内存不足+;因为制造新的物体,c++,object,heap,nodes,montecarlo,C++,Object,Heap,Nodes,Montecarlo,所以我试图为奥赛罗游戏实现一个蒙特卡罗搜索树。我有一个根节点和子节点,其中“x”是“y”的子节点,如果您可以在一次合法移动中从“y”移动到“x” 在每个节点上,我存储一个“Board”对象,该对象保存所有的Board信息,例如每个tile的值。我遇到的第一个问题是,如果我更改子节点的board对象,它也会更改父节点的值。我通过为每个子节点创建一个“新”的Board对象修复了这个问题,但是当我运行模拟几千次时,这会导致使用过多的内存,以至于内存耗尽 我只是想知道是否有一种方法可以改变子节点中的线路

所以我试图为奥赛罗游戏实现一个蒙特卡罗搜索树。我有一个根节点和子节点,其中“x”是“y”的子节点,如果您可以在一次合法移动中从“y”移动到“x”

在每个节点上,我存储一个“Board”对象,该对象保存所有的Board信息,例如每个tile的值。我遇到的第一个问题是,如果我更改子节点的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;
    }
for(int x=0;xgetCurrentBoard();
//检索板值信息
int**temporaryBoardValues=currentBoard->getBoardValues();
//使用以前的参数创建新的board对象
线路板*临时线路板=新线路板(块尺寸、线路板尺寸、偏移量);
//将新板值设置为与旧板值相同
临时董事会->设置董事会价值观(临时董事会价值观);
//创建该板状态的克隆
//板*temporaryBoard=cloneBoard(*currentBoard);
//创建具有克隆板状态的节点,将父节点设置为要展开的节点。
//为其指定一个可用移动
//生成子节点的数组
myChildren[x]=新节点(nodeToExpand,temporaryBoard,availableMoves[x],currentPlayer);
//删除临时董事会;
}

小代码段。这是我创建一个新的Board对象的部分,该对象会耗尽所有内存。

蒙特卡罗树搜索(MCTS)的典型实现不会使用任何技巧来显式避免内存耗尽。从理论上讲,如果你继续模拟,你的内存确实会耗尽,但这通常不只是你在OP中提到的几千次模拟

现在,大多数MCT的实现在每次模拟时只将树扩展一个节点。您发布的代码看起来像是在为每个模拟向树添加
b
节点,其中
b
是分支因子(子节点数)。所以这是你可以考虑改变的

此外,您可以查看一下Board类中存储的内容,并确保您实际上只存储了必要的内容,而没有其他内容。只有游戏状态的数据,没有更多。例如,确保其中没有任何仅用于GUI的数据(这是我多年前犯的一个错误)

如果你在浏览这两个点之后仍然存在内存问题,你可以考虑JigdSpple的评论。您可以存储移动而不是板状态,并在模拟中通过节点运行时重新构造板状态。这将显著减少内存消耗,但也会增加每次模拟的处理时间。如果你每回合只有有限的思考时间,这会导致一个较弱的玩家


最后,考虑到您正在使用我在您发布的代码中看到的
new
操作进行手动内存管理,您总是可能忘记了某个匹配的
delete
,导致内存泄漏。如果在查看以上几点后,仅通过几千次模拟仍然存在内存问题,这是最可能的原因,因为MCT在达到远高于几千的模拟计数之前不应该遇到内存问题。

您可以发布一个小的代码示例吗?对于深度为
n
的分支树搜索:您只需要在内存中保留(1)当前的最佳移动和
n
节点。您不需要只保留完整的树,只需沿1个分支进行当前搜索/评估,以达到深度
n
,这可以很容易地保留在堆栈上-如果您在堆上保留了许多板,则可能是做错了。(另请参见alpha-beta算法)。那么,为什么不将移动存储在节点中,并根据从根节点到达节点n所需的顺序节点中的移动顺序在节点n处构建电路板呢?@MatthewFennell Advice——在编写一行代码之前,应该在设计中考虑内存需求。最终可能发生的事情是,如果不是所有当前代码的话,也必须大量地废弃。从维基百科关于蒙特卡洛搜索树的文章的非常肤浅的阅读来看,在我看来,这是一种很好的理论方法,也是一种可怕的实际方法。我已经设法修复了创建多个board对象的内存泄漏问题,正如您现在提到的那样,按照jaggedSpire提到的存储操作。我对MCT的一般方法是从根开始,如果它已被扩展,则根据其置信上限选择正确的子项。如果它没有被扩展,那么就扩展它并进行随机模拟,直到游戏结束。但我确实有一个问题,在计算机的每次移动中,它都会生成大量新节点,但每次移动后这些节点都会保存在内存中,因此随着游戏的进行,内存会被旧节点信息阻塞,只是我真的不知道如何释放它memory@MatthewFennell您的意思是,内存使用量增加是因为您在实际移动后没有清理搜索树吗